1 /*
2 * gpg.c
3 * vim: expandtab:ts=4:sts=4:sw=4
4 *
5 * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
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
36 #include "config.h"
37
38 #include <locale.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <errno.h>
42 #include <sys/stat.h>
43
44 #include <glib.h>
45 #include <glib/gstdio.h>
46 #include <gpgme.h>
47
48 #include "log.h"
49 #include "common.h"
50 #include "pgp/gpg.h"
51 #include "config/files.h"
52 #include "tools/autocomplete.h"
53 #include "ui/ui.h"
54
55 #define PGP_SIGNATURE_HEADER "-----BEGIN PGP SIGNATURE-----"
56 #define PGP_SIGNATURE_FOOTER "-----END PGP SIGNATURE-----"
57 #define PGP_MESSAGE_HEADER "-----BEGIN PGP MESSAGE-----"
58 #define PGP_MESSAGE_FOOTER "-----END PGP MESSAGE-----"
59
60 static const char* libversion = NULL;
61 static GHashTable* pubkeys;
62
63 static gchar* pubsloc;
64 static GKeyFile* pubkeyfile;
65
66 static char* passphrase;
67 static char* passphrase_attempt;
68
69 static Autocomplete key_ac;
70
71 static char* _remove_header_footer(char* str, const char* const footer);
72 static char* _add_header_footer(const char* const str, const char* const header, const char* const footer);
73 static void _save_pubkeys(void);
74
75 static gpgme_key_t _ox_key_lookup(const char* const barejid, gboolean secret_only);
76 static gboolean _ox_key_is_usable(gpgme_key_t key, const char* const barejid, gboolean secret);
77
78 void
_p_gpg_free_pubkeyid(ProfPGPPubKeyId * pubkeyid)79 _p_gpg_free_pubkeyid(ProfPGPPubKeyId* pubkeyid)
80 {
81 if (pubkeyid) {
82 free(pubkeyid->id);
83 }
84 free(pubkeyid);
85 }
86
87 static gpgme_error_t*
_p_gpg_passphrase_cb(void * hook,const char * uid_hint,const char * passphrase_info,int prev_was_bad,int fd)88 _p_gpg_passphrase_cb(void* hook, const char* uid_hint, const char* passphrase_info, int prev_was_bad, int fd)
89 {
90 if (passphrase) {
91 gpgme_io_write(fd, passphrase, strlen(passphrase));
92 } else {
93 GString* pass_term = g_string_new("");
94
95 char* password = ui_ask_pgp_passphrase(uid_hint, prev_was_bad);
96 if (password) {
97 g_string_append(pass_term, password);
98 free(password);
99 }
100
101 g_string_append(pass_term, "\n");
102 if (passphrase_attempt) {
103 free(passphrase_attempt);
104 }
105 passphrase_attempt = pass_term->str;
106 g_string_free(pass_term, FALSE);
107
108 gpgme_io_write(fd, passphrase_attempt, strlen(passphrase_attempt));
109 }
110
111 return 0;
112 }
113
114 void
p_gpg_init(void)115 p_gpg_init(void)
116 {
117 libversion = gpgme_check_version(NULL);
118 log_debug("GPG: Found gpgme version: %s", libversion);
119 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
120
121 pubkeys = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_p_gpg_free_pubkeyid);
122
123 key_ac = autocomplete_new();
124 GHashTable* keys = p_gpg_list_keys();
125 p_gpg_free_keys(keys);
126
127 passphrase = NULL;
128 passphrase_attempt = NULL;
129 }
130
131 void
p_gpg_close(void)132 p_gpg_close(void)
133 {
134 if (pubkeys) {
135 g_hash_table_destroy(pubkeys);
136 pubkeys = NULL;
137 }
138
139 if (pubkeyfile) {
140 g_key_file_free(pubkeyfile);
141 pubkeyfile = NULL;
142 }
143
144 free(pubsloc);
145 pubsloc = NULL;
146
147 autocomplete_free(key_ac);
148 key_ac = NULL;
149
150 if (passphrase) {
151 free(passphrase);
152 passphrase = NULL;
153 }
154
155 if (passphrase_attempt) {
156 free(passphrase_attempt);
157 passphrase_attempt = NULL;
158 }
159 }
160
161 void
p_gpg_on_connect(const char * const barejid)162 p_gpg_on_connect(const char* const barejid)
163 {
164 gchar* pubsfile = files_get_account_data_path(DIR_PGP, barejid);
165
166 // mkdir if doesn't exist for account
167 errno = 0;
168 int res = g_mkdir_with_parents(pubsfile, S_IRWXU);
169 if (res == -1) {
170 const char* errmsg = strerror(errno);
171 if (errmsg) {
172 log_error("Error creating directory: %s, %s", pubsfile, errmsg);
173 } else {
174 log_error("Error creating directory: %s", pubsfile);
175 }
176 }
177
178 // create or read publickeys
179 GString* pubtmp = g_string_new(pubsfile);
180 g_string_append(pubtmp, "/pubkeys");
181 pubsloc = pubtmp->str;
182 g_string_free(pubtmp, FALSE);
183 g_free(pubsfile);
184
185 if (g_file_test(pubsloc, G_FILE_TEST_EXISTS)) {
186 g_chmod(pubsloc, S_IRUSR | S_IWUSR);
187 }
188
189 pubkeyfile = g_key_file_new();
190 g_key_file_load_from_file(pubkeyfile, pubsloc, G_KEY_FILE_KEEP_COMMENTS, NULL);
191
192 // load each keyid
193 gsize len = 0;
194 gchar** jids = g_key_file_get_groups(pubkeyfile, &len);
195
196 gpgme_ctx_t ctx;
197 gpgme_error_t error = gpgme_new(&ctx);
198
199 if (error) {
200 log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
201 g_strfreev(jids);
202 return;
203 }
204
205 for (int i = 0; i < len; i++) {
206 GError* gerr = NULL;
207 gchar* jid = jids[i];
208 gchar* keyid = g_key_file_get_string(pubkeyfile, jid, "keyid", &gerr);
209 if (gerr) {
210 log_error("Error loading PGP key id for %s", jid);
211 g_error_free(gerr);
212 g_free(keyid);
213 } else {
214 gpgme_key_t key = NULL;
215 error = gpgme_get_key(ctx, keyid, &key, 0);
216 if (error || key == NULL) {
217 log_warning("GPG: Failed to get key for %s: %s %s", jid, gpgme_strsource(error), gpgme_strerror(error));
218 continue;
219 }
220
221 ProfPGPPubKeyId* pubkeyid = malloc(sizeof(ProfPGPPubKeyId));
222 pubkeyid->id = strdup(keyid);
223 pubkeyid->received = FALSE;
224 g_hash_table_replace(pubkeys, strdup(jid), pubkeyid);
225 g_free(keyid);
226 gpgme_key_unref(key);
227 }
228 }
229
230 gpgme_release(ctx);
231 g_strfreev(jids);
232
233 _save_pubkeys();
234 }
235
236 void
p_gpg_on_disconnect(void)237 p_gpg_on_disconnect(void)
238 {
239 if (pubkeys) {
240 g_hash_table_destroy(pubkeys);
241 pubkeys = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_p_gpg_free_pubkeyid);
242 }
243
244 if (pubkeyfile) {
245 g_key_file_free(pubkeyfile);
246 pubkeyfile = NULL;
247 }
248
249 free(pubsloc);
250 pubsloc = NULL;
251
252 if (passphrase) {
253 free(passphrase);
254 passphrase = NULL;
255 }
256
257 if (passphrase_attempt) {
258 free(passphrase_attempt);
259 passphrase_attempt = NULL;
260 }
261 }
262
263 gboolean
p_gpg_addkey(const char * const jid,const char * const keyid)264 p_gpg_addkey(const char* const jid, const char* const keyid)
265 {
266 gpgme_ctx_t ctx;
267 gpgme_error_t error = gpgme_new(&ctx);
268 if (error) {
269 log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
270 return FALSE;
271 }
272
273 gpgme_key_t key = NULL;
274 error = gpgme_get_key(ctx, keyid, &key, 0);
275 gpgme_release(ctx);
276
277 if (error || key == NULL) {
278 log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error));
279 return FALSE;
280 }
281
282 // save to public key file
283 g_key_file_set_string(pubkeyfile, jid, "keyid", keyid);
284 _save_pubkeys();
285
286 // update in memory pubkeys list
287 ProfPGPPubKeyId* pubkeyid = malloc(sizeof(ProfPGPPubKeyId));
288 pubkeyid->id = strdup(keyid);
289 pubkeyid->received = FALSE;
290 g_hash_table_replace(pubkeys, strdup(jid), pubkeyid);
291 gpgme_key_unref(key);
292
293 return TRUE;
294 }
295
296 static ProfPGPKey*
_p_gpg_key_new(void)297 _p_gpg_key_new(void)
298 {
299 ProfPGPKey* p_pgpkey = malloc(sizeof(ProfPGPKey));
300 p_pgpkey->id = NULL;
301 p_pgpkey->name = NULL;
302 p_pgpkey->fp = NULL;
303 p_pgpkey->encrypt = FALSE;
304 p_pgpkey->sign = FALSE;
305 p_pgpkey->certify = FALSE;
306 p_pgpkey->authenticate = FALSE;
307 p_pgpkey->secret = FALSE;
308
309 return p_pgpkey;
310 }
311
312 static void
_p_gpg_free_key(ProfPGPKey * key)313 _p_gpg_free_key(ProfPGPKey* key)
314 {
315 if (key) {
316 free(key->id);
317 free(key->name);
318 free(key->fp);
319 free(key);
320 }
321 }
322
323 GHashTable*
p_gpg_list_keys(void)324 p_gpg_list_keys(void)
325 {
326 gpgme_error_t error;
327 GHashTable* result = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_p_gpg_free_key);
328
329 gpgme_ctx_t ctx;
330 error = gpgme_new(&ctx);
331
332 if (error) {
333 log_error("GPG: Could not list keys. %s %s", gpgme_strsource(error), gpgme_strerror(error));
334 return NULL;
335 }
336
337 error = gpgme_op_keylist_start(ctx, NULL, 0);
338 if (error == GPG_ERR_NO_ERROR) {
339 gpgme_key_t key;
340 error = gpgme_op_keylist_next(ctx, &key);
341 while (!error) {
342 gpgme_subkey_t sub = key->subkeys;
343
344 ProfPGPKey* p_pgpkey = _p_gpg_key_new();
345 p_pgpkey->id = strdup(sub->keyid);
346 p_pgpkey->name = strdup(key->uids->uid);
347 p_pgpkey->fp = strdup(sub->fpr);
348 if (sub->can_encrypt)
349 p_pgpkey->encrypt = TRUE;
350 if (sub->can_authenticate)
351 p_pgpkey->authenticate = TRUE;
352 if (sub->can_certify)
353 p_pgpkey->certify = TRUE;
354 if (sub->can_sign)
355 p_pgpkey->sign = TRUE;
356
357 sub = sub->next;
358 while (sub) {
359 if (sub->can_encrypt)
360 p_pgpkey->encrypt = TRUE;
361 if (sub->can_authenticate)
362 p_pgpkey->authenticate = TRUE;
363 if (sub->can_certify)
364 p_pgpkey->certify = TRUE;
365 if (sub->can_sign)
366 p_pgpkey->sign = TRUE;
367
368 sub = sub->next;
369 }
370
371 g_hash_table_insert(result, strdup(p_pgpkey->name), p_pgpkey);
372
373 gpgme_key_unref(key);
374 error = gpgme_op_keylist_next(ctx, &key);
375 }
376 }
377
378 error = gpgme_op_keylist_start(ctx, NULL, 1);
379 if (error == GPG_ERR_NO_ERROR) {
380 gpgme_key_t key;
381 error = gpgme_op_keylist_next(ctx, &key);
382 while (!error) {
383 gpgme_subkey_t sub = key->subkeys;
384 while (sub) {
385 if (sub->secret) {
386 ProfPGPKey* p_pgpkey = g_hash_table_lookup(result, key->uids->uid);
387 if (p_pgpkey) {
388 p_pgpkey->secret = TRUE;
389 }
390 }
391 sub = sub->next;
392 }
393
394 gpgme_key_unref(key);
395 error = gpgme_op_keylist_next(ctx, &key);
396 }
397 }
398
399 gpgme_release(ctx);
400
401 autocomplete_clear(key_ac);
402 GList* ids = g_hash_table_get_keys(result);
403 GList* curr = ids;
404 while (curr) {
405 ProfPGPKey* key = g_hash_table_lookup(result, curr->data);
406 autocomplete_add(key_ac, key->id);
407 curr = curr->next;
408 }
409 g_list_free(ids);
410
411 return result;
412 }
413
414 void
p_gpg_free_keys(GHashTable * keys)415 p_gpg_free_keys(GHashTable* keys)
416 {
417 g_hash_table_destroy(keys);
418 }
419
420 GHashTable*
p_gpg_pubkeys(void)421 p_gpg_pubkeys(void)
422 {
423 return pubkeys;
424 }
425
426 const char*
p_gpg_libver(void)427 p_gpg_libver(void)
428 {
429 if (libversion == NULL) {
430 libversion = gpgme_check_version(NULL);
431 }
432 return libversion;
433 }
434
435 gboolean
p_gpg_valid_key(const char * const keyid,char ** err_str)436 p_gpg_valid_key(const char* const keyid, char** err_str)
437 {
438 gpgme_ctx_t ctx;
439 gpgme_error_t error = gpgme_new(&ctx);
440 if (error) {
441 log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
442 *err_str = strdup(gpgme_strerror(error));
443 return FALSE;
444 }
445
446 gpgme_key_t key = NULL;
447 error = gpgme_get_key(ctx, keyid, &key, 1);
448
449 if (error || key == NULL) {
450 log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error));
451 *err_str = strdup(gpgme_strerror(error));
452 gpgme_release(ctx);
453 return FALSE;
454 }
455
456 if (key == NULL) {
457 *err_str = strdup("Unknown error");
458 gpgme_release(ctx);
459 return FALSE;
460 }
461
462 gpgme_release(ctx);
463 gpgme_key_unref(key);
464 return TRUE;
465 }
466
467 gboolean
p_gpg_available(const char * const barejid)468 p_gpg_available(const char* const barejid)
469 {
470 char* pubkey = g_hash_table_lookup(pubkeys, barejid);
471 return (pubkey != NULL);
472 }
473
474 void
p_gpg_verify(const char * const barejid,const char * const sign)475 p_gpg_verify(const char* const barejid, const char* const sign)
476 {
477 if (!sign) {
478 return;
479 }
480
481 gpgme_ctx_t ctx;
482 gpgme_error_t error = gpgme_new(&ctx);
483
484 if (error) {
485 log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
486 return;
487 }
488
489 char* sign_with_header_footer = _add_header_footer(sign, PGP_SIGNATURE_HEADER, PGP_SIGNATURE_FOOTER);
490 gpgme_data_t sign_data;
491 gpgme_data_new_from_mem(&sign_data, sign_with_header_footer, strlen(sign_with_header_footer), 1);
492 free(sign_with_header_footer);
493
494 gpgme_data_t plain_data;
495 gpgme_data_new(&plain_data);
496
497 error = gpgme_op_verify(ctx, sign_data, NULL, plain_data);
498 gpgme_data_release(sign_data);
499 gpgme_data_release(plain_data);
500
501 if (error) {
502 log_error("GPG: Failed to verify. %s %s", gpgme_strsource(error), gpgme_strerror(error));
503 gpgme_release(ctx);
504 return;
505 }
506
507 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
508 if (result) {
509 if (result->signatures) {
510 gpgme_key_t key = NULL;
511 error = gpgme_get_key(ctx, result->signatures->fpr, &key, 0);
512 if (error) {
513 log_debug("Could not find PGP key with ID %s for %s", result->signatures->fpr, barejid);
514 } else {
515 log_debug("Fingerprint found for %s: %s ", barejid, key->subkeys->fpr);
516 ProfPGPPubKeyId* pubkeyid = malloc(sizeof(ProfPGPPubKeyId));
517 pubkeyid->id = strdup(key->subkeys->keyid);
518 pubkeyid->received = TRUE;
519 g_hash_table_replace(pubkeys, strdup(barejid), pubkeyid);
520 }
521
522 gpgme_key_unref(key);
523 }
524 }
525
526 gpgme_release(ctx);
527 }
528
529 char*
p_gpg_sign(const char * const str,const char * const fp)530 p_gpg_sign(const char* const str, const char* const fp)
531 {
532 gpgme_ctx_t ctx;
533 gpgme_error_t error = gpgme_new(&ctx);
534 if (error) {
535 log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
536 return NULL;
537 }
538
539 gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t)_p_gpg_passphrase_cb, NULL);
540
541 gpgme_key_t key = NULL;
542 error = gpgme_get_key(ctx, fp, &key, 1);
543
544 if (error || key == NULL) {
545 log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error));
546 gpgme_release(ctx);
547 return NULL;
548 }
549
550 gpgme_signers_clear(ctx);
551 error = gpgme_signers_add(ctx, key);
552 gpgme_key_unref(key);
553
554 if (error) {
555 log_error("GPG: Failed to load signer. %s %s", gpgme_strsource(error), gpgme_strerror(error));
556 gpgme_release(ctx);
557 return NULL;
558 }
559
560 char* str_or_empty = NULL;
561 if (str) {
562 str_or_empty = strdup(str);
563 } else {
564 str_or_empty = strdup("");
565 }
566 gpgme_data_t str_data;
567 gpgme_data_new_from_mem(&str_data, str_or_empty, strlen(str_or_empty), 1);
568 free(str_or_empty);
569
570 gpgme_data_t signed_data;
571 gpgme_data_new(&signed_data);
572
573 gpgme_set_armor(ctx, 1);
574 error = gpgme_op_sign(ctx, str_data, signed_data, GPGME_SIG_MODE_DETACH);
575 gpgme_data_release(str_data);
576 gpgme_release(ctx);
577
578 if (error) {
579 log_error("GPG: Failed to sign string. %s %s", gpgme_strsource(error), gpgme_strerror(error));
580 gpgme_data_release(signed_data);
581 return NULL;
582 }
583
584 char* result = NULL;
585
586 size_t len = 0;
587 char* signed_str = gpgme_data_release_and_get_mem(signed_data, &len);
588 if (signed_str) {
589 GString* signed_gstr = g_string_new("");
590 g_string_append_len(signed_gstr, signed_str, len);
591 result = _remove_header_footer(signed_gstr->str, PGP_SIGNATURE_FOOTER);
592 g_string_free(signed_gstr, TRUE);
593 gpgme_free(signed_str);
594 }
595
596 if (passphrase_attempt) {
597 passphrase = strdup(passphrase_attempt);
598 }
599
600 return result;
601 }
602
603 char*
p_gpg_encrypt(const char * const barejid,const char * const message,const char * const fp)604 p_gpg_encrypt(const char* const barejid, const char* const message, const char* const fp)
605 {
606 ProfPGPPubKeyId* pubkeyid = g_hash_table_lookup(pubkeys, barejid);
607 if (!pubkeyid) {
608 return NULL;
609 }
610 if (!pubkeyid->id) {
611 return NULL;
612 }
613
614 gpgme_key_t keys[3];
615
616 keys[0] = NULL;
617 keys[1] = NULL;
618 keys[2] = NULL;
619
620 gpgme_ctx_t ctx;
621 gpgme_error_t error = gpgme_new(&ctx);
622 if (error) {
623 log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
624 return NULL;
625 }
626
627 gpgme_key_t receiver_key;
628 error = gpgme_get_key(ctx, pubkeyid->id, &receiver_key, 0);
629 if (error || receiver_key == NULL) {
630 log_error("GPG: Failed to get receiver_key. %s %s", gpgme_strsource(error), gpgme_strerror(error));
631 gpgme_release(ctx);
632 return NULL;
633 }
634 keys[0] = receiver_key;
635
636 gpgme_key_t sender_key = NULL;
637 error = gpgme_get_key(ctx, fp, &sender_key, 0);
638 if (error || sender_key == NULL) {
639 log_error("GPG: Failed to get sender_key. %s %s", gpgme_strsource(error), gpgme_strerror(error));
640 gpgme_release(ctx);
641 return NULL;
642 }
643 keys[1] = sender_key;
644
645 gpgme_data_t plain;
646 gpgme_data_new_from_mem(&plain, message, strlen(message), 1);
647
648 gpgme_data_t cipher;
649 gpgme_data_new(&cipher);
650
651 gpgme_set_armor(ctx, 1);
652 error = gpgme_op_encrypt(ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher);
653 gpgme_data_release(plain);
654 gpgme_release(ctx);
655 gpgme_key_unref(receiver_key);
656 gpgme_key_unref(sender_key);
657
658 if (error) {
659 log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error));
660 return NULL;
661 }
662
663 size_t len;
664 char* cipher_str = gpgme_data_release_and_get_mem(cipher, &len);
665
666 char* result = NULL;
667 if (cipher_str) {
668 GString* cipher_gstr = g_string_new("");
669 g_string_append_len(cipher_gstr, cipher_str, len);
670 result = _remove_header_footer(cipher_gstr->str, PGP_MESSAGE_FOOTER);
671 g_string_free(cipher_gstr, TRUE);
672 gpgme_free(cipher_str);
673 }
674
675 return result;
676 }
677
678 char*
p_gpg_decrypt(const char * const cipher)679 p_gpg_decrypt(const char* const cipher)
680 {
681 gpgme_ctx_t ctx;
682 gpgme_error_t error = gpgme_new(&ctx);
683
684 if (error) {
685 log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
686 return NULL;
687 }
688
689 gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t)_p_gpg_passphrase_cb, NULL);
690
691 char* cipher_with_headers = _add_header_footer(cipher, PGP_MESSAGE_HEADER, PGP_MESSAGE_FOOTER);
692 gpgme_data_t cipher_data;
693 gpgme_data_new_from_mem(&cipher_data, cipher_with_headers, strlen(cipher_with_headers), 1);
694 free(cipher_with_headers);
695
696 gpgme_data_t plain_data;
697 gpgme_data_new(&plain_data);
698
699 error = gpgme_op_decrypt(ctx, cipher_data, plain_data);
700 gpgme_data_release(cipher_data);
701
702 if (error) {
703 log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error));
704 gpgme_data_release(plain_data);
705 gpgme_release(ctx);
706 return NULL;
707 }
708
709 gpgme_decrypt_result_t res = gpgme_op_decrypt_result(ctx);
710 if (res) {
711 GString* recipients_str = g_string_new("");
712 gpgme_recipient_t recipient = res->recipients;
713 while (recipient) {
714 gpgme_key_t key;
715 error = gpgme_get_key(ctx, recipient->keyid, &key, 1);
716
717 if (!error && key) {
718 const char* addr = gpgme_key_get_string_attr(key, GPGME_ATTR_EMAIL, NULL, 0);
719 if (addr) {
720 g_string_append(recipients_str, addr);
721 }
722 gpgme_key_unref(key);
723 }
724
725 if (recipient->next) {
726 g_string_append(recipients_str, ", ");
727 }
728
729 recipient = recipient->next;
730 }
731
732 log_debug("GPG: Decrypted message for recipients: %s", recipients_str->str);
733 g_string_free(recipients_str, TRUE);
734 }
735 gpgme_release(ctx);
736
737 size_t len = 0;
738 char* plain_str = gpgme_data_release_and_get_mem(plain_data, &len);
739 char* result = NULL;
740 if (plain_str) {
741 plain_str[len] = 0;
742 result = g_strdup(plain_str);
743 }
744 gpgme_free(plain_str);
745
746 if (passphrase_attempt) {
747 passphrase = strdup(passphrase_attempt);
748 }
749
750 return result;
751 }
752
753 void
p_gpg_free_decrypted(char * decrypted)754 p_gpg_free_decrypted(char* decrypted)
755 {
756 g_free(decrypted);
757 }
758
759 char*
p_gpg_autocomplete_key(const char * const search_str,gboolean previous,void * context)760 p_gpg_autocomplete_key(const char* const search_str, gboolean previous, void* context)
761 {
762 return autocomplete_complete(key_ac, search_str, TRUE, previous);
763 }
764
765 void
p_gpg_autocomplete_key_reset(void)766 p_gpg_autocomplete_key_reset(void)
767 {
768 autocomplete_reset(key_ac);
769 }
770
771 char*
p_gpg_format_fp_str(char * fp)772 p_gpg_format_fp_str(char* fp)
773 {
774 if (!fp) {
775 return NULL;
776 }
777
778 GString* format = g_string_new("");
779 int len = strlen(fp);
780 for (int i = 0; i < len; i++) {
781 g_string_append_c(format, fp[i]);
782 if (((i + 1) % 4 == 0) && (i + 1 < len)) {
783 g_string_append_c(format, ' ');
784 }
785 }
786
787 char* result = format->str;
788 g_string_free(format, FALSE);
789
790 return result;
791 }
792
793 /*!
794 * \brief Public keys with XMPP-URI.
795 *
796 * This function will look for all public key with a XMPP-URI as UID.
797 *
798 */
799 GHashTable*
ox_gpg_public_keys(void)800 ox_gpg_public_keys(void)
801 {
802 gpgme_error_t error;
803 GHashTable* result = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_p_gpg_free_key);
804
805 gpgme_ctx_t ctx;
806 error = gpgme_new(&ctx);
807
808 if (error) {
809 log_error("OX - gpgme_new failed: %s %s", gpgme_strsource(error), gpgme_strerror(error));
810 return NULL;
811 }
812
813 error = gpgme_op_keylist_start(ctx, NULL, 0); // all public keys
814 if (error == GPG_ERR_NO_ERROR) {
815 gpgme_key_t key;
816 error = gpgme_op_keylist_next(ctx, &key);
817 if (error != GPG_ERR_EOF && error != GPG_ERR_NO_ERROR) {
818 log_error("OX: gpgme_op_keylist_next %s %s", gpgme_strsource(error), gpgme_strerror(error));
819 g_hash_table_destroy(result);
820 return NULL;
821 }
822 while (!error) {
823 // Looking for XMPP URI UID
824 gpgme_user_id_t uid = key->uids;
825 gpgme_user_id_t xmppid = NULL;
826 while (!xmppid && uid) {
827 if (uid->name && strlen(uid->name) >= 10) {
828 if (strstr(uid->name, "xmpp:") == uid->name) {
829 xmppid = uid;
830 }
831 }
832 uid = uid->next;
833 }
834
835 if (xmppid) {
836 // Build Key information about all subkey
837 gpgme_subkey_t sub = key->subkeys;
838
839 ProfPGPKey* p_pgpkey = _p_gpg_key_new();
840 p_pgpkey->id = strdup(sub->keyid);
841 p_pgpkey->name = strdup(xmppid->uid);
842 p_pgpkey->fp = strdup(sub->fpr);
843 if (sub->can_encrypt)
844 p_pgpkey->encrypt = TRUE;
845 if (sub->can_authenticate)
846 p_pgpkey->authenticate = TRUE;
847 if (sub->can_certify)
848 p_pgpkey->certify = TRUE;
849 if (sub->can_sign)
850 p_pgpkey->sign = TRUE;
851
852 sub = sub->next;
853 while (sub) {
854 if (sub->can_encrypt)
855 p_pgpkey->encrypt = TRUE;
856 if (sub->can_authenticate)
857 p_pgpkey->authenticate = TRUE;
858 if (sub->can_certify)
859 p_pgpkey->certify = TRUE;
860 if (sub->can_sign)
861 p_pgpkey->sign = TRUE;
862
863 sub = sub->next;
864 }
865
866 g_hash_table_insert(result, strdup(p_pgpkey->name), p_pgpkey);
867 }
868 gpgme_key_unref(key);
869 error = gpgme_op_keylist_next(ctx, &key);
870 }
871 }
872 gpgme_release(ctx);
873
874 //autocomplete_clear(key_ac);
875 // GList *ids = g_hash_table_get_keys(result);
876 // GList *curr = ids;
877 // while (curr) {
878 // ProfPGPKey *key = g_hash_table_lookup(result, curr->data);
879 // autocomplete_add(key_ac, key->id);
880 // curr = curr->next;
881 // }
882 // g_list_free(ids);
883
884 return result;
885 }
886
887 char*
p_ox_gpg_signcrypt(const char * const sender_barejid,const char * const recipient_barejid,const char * const message)888 p_ox_gpg_signcrypt(const char* const sender_barejid, const char* const recipient_barejid, const char* const message)
889 {
890 setlocale(LC_ALL, "");
891 gpgme_check_version(NULL);
892 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
893 gpgme_ctx_t ctx;
894
895 gpgme_error_t error = gpgme_new(&ctx);
896 if (GPG_ERR_NO_ERROR != error) {
897 printf("gpgme_new: %d\n", error);
898 return NULL;
899 }
900
901 error = gpgme_set_protocol(ctx, GPGME_PROTOCOL_OPENPGP);
902 if (error != 0) {
903 log_error("GpgME Error: %s", gpgme_strerror(error));
904 }
905
906 gpgme_set_armor(ctx, 0);
907 gpgme_set_textmode(ctx, 0);
908 gpgme_set_offline(ctx, 1);
909 gpgme_set_keylist_mode(ctx, GPGME_KEYLIST_MODE_LOCAL);
910 if (error != 0) {
911 log_error("GpgME Error: %s", gpgme_strerror(error));
912 }
913
914 gpgme_key_t recp[3];
915 recp[0] = NULL,
916 recp[1] = NULL;
917
918 char* xmpp_jid_me = alloca((strlen(sender_barejid) + 6) * sizeof(char));
919 char* xmpp_jid_recipient = alloca((strlen(recipient_barejid) + 6) * sizeof(char));
920
921 strcpy(xmpp_jid_me, "xmpp:");
922 strcpy(xmpp_jid_recipient, "xmpp:");
923 strcat(xmpp_jid_me, sender_barejid);
924 strcat(xmpp_jid_recipient, recipient_barejid);
925
926 gpgme_signers_clear(ctx);
927
928 // lookup own key
929 recp[0] = _ox_key_lookup(sender_barejid, TRUE);
930 if (error != 0) {
931 log_error("Key not found for %s. GpgME Error: %s", xmpp_jid_me, gpgme_strerror(error));
932 return NULL;
933 }
934
935 error = gpgme_signers_add(ctx, recp[0]);
936 if (error != 0) {
937 log_error("gpgme_signers_add %s. GpgME Error: %s", xmpp_jid_me, gpgme_strerror(error));
938 return NULL;
939 }
940
941 // lookup key of recipient
942 recp[1] = _ox_key_lookup(recipient_barejid, FALSE);
943 if (error != 0) {
944 log_error("Key not found for %s. GpgME Error: %s", xmpp_jid_recipient, gpgme_strerror(error));
945 return NULL;
946 }
947 recp[2] = NULL;
948 log_debug("%s <%s>", recp[0]->uids->name, recp[0]->uids->email);
949 log_debug("%s <%s>", recp[1]->uids->name, recp[1]->uids->email);
950
951 gpgme_encrypt_flags_t flags = 0;
952
953 gpgme_data_t plain;
954 gpgme_data_t cipher;
955
956 error = gpgme_data_new(&plain);
957 if (error != 0) {
958 log_error("GpgME Error: %s", gpgme_strerror(error));
959 return NULL;
960 }
961
962 error = gpgme_data_new_from_mem(&plain, message, strlen(message), 0);
963 if (error != 0) {
964 log_error("GpgME Error: %s", gpgme_strerror(error));
965 return NULL;
966 }
967 error = gpgme_data_new(&cipher);
968 if (error != 0) {
969 log_error("GpgME Error: %s", gpgme_strerror(error));
970 return NULL;
971 }
972
973 error = gpgme_op_encrypt_sign(ctx, recp, flags, plain, cipher);
974 if (error != 0) {
975 log_error("GpgME Error: %s", gpgme_strerror(error));
976 return NULL;
977 }
978
979 size_t len;
980 char* cipher_str = gpgme_data_release_and_get_mem(cipher, &len);
981 char* result = g_base64_encode((unsigned char*)cipher_str, len);
982 gpgme_key_release(recp[0]);
983 gpgme_key_release(recp[1]);
984 gpgme_release(ctx);
985 return result;
986 }
987
988 gboolean
ox_is_private_key_available(const char * const barejid)989 ox_is_private_key_available(const char* const barejid)
990 {
991 g_assert(barejid);
992 gboolean result = FALSE;
993
994 gpgme_key_t key = _ox_key_lookup(barejid, TRUE);
995 if (key) {
996 if (_ox_key_is_usable(key, barejid, TRUE)) {
997 result = TRUE;
998 }
999 gpgme_key_unref(key);
1000 }
1001
1002 return result;
1003 }
1004
1005 gboolean
ox_is_public_key_available(const char * const barejid)1006 ox_is_public_key_available(const char* const barejid)
1007 {
1008 g_assert(barejid);
1009 gboolean result = FALSE;
1010 gpgme_key_t key = _ox_key_lookup(barejid, FALSE);
1011 if (key) {
1012 if (_ox_key_is_usable(key, barejid, FALSE)) {
1013 result = TRUE;
1014 }
1015 gpgme_key_unref(key);
1016 }
1017 return result;
1018 }
1019
1020 static char*
_remove_header_footer(char * str,const char * const footer)1021 _remove_header_footer(char* str, const char* const footer)
1022 {
1023 int pos = 0;
1024 int newlines = 0;
1025
1026 while (newlines < 2) {
1027 if (str[pos] == '\n') {
1028 newlines++;
1029 }
1030 pos++;
1031
1032 if (str[pos] == '\0') {
1033 return NULL;
1034 }
1035 }
1036
1037 char* stripped = strdup(&str[pos]);
1038 char* footer_start = g_strrstr(stripped, footer);
1039 footer_start[0] = '\0';
1040
1041 return stripped;
1042 }
1043
1044 static char*
_add_header_footer(const char * const str,const char * const header,const char * const footer)1045 _add_header_footer(const char* const str, const char* const header, const char* const footer)
1046 {
1047 GString* result_str = g_string_new("");
1048
1049 g_string_append(result_str, header);
1050 g_string_append(result_str, "\n\n");
1051 g_string_append(result_str, str);
1052 g_string_append(result_str, "\n");
1053 g_string_append(result_str, footer);
1054
1055 char* result = result_str->str;
1056 g_string_free(result_str, FALSE);
1057
1058 return result;
1059 }
1060
1061 static void
_save_pubkeys(void)1062 _save_pubkeys(void)
1063 {
1064 gsize g_data_size;
1065 gchar* g_pubkeys_data = g_key_file_to_data(pubkeyfile, &g_data_size, NULL);
1066 g_file_set_contents(pubsloc, g_pubkeys_data, g_data_size, NULL);
1067 g_chmod(pubsloc, S_IRUSR | S_IWUSR);
1068 g_free(g_pubkeys_data);
1069 }
1070
1071 static gpgme_key_t
_ox_key_lookup(const char * const barejid,gboolean secret_only)1072 _ox_key_lookup(const char* const barejid, gboolean secret_only)
1073 {
1074 g_assert(barejid);
1075 log_debug("Looking for %s key: %s", secret_only == TRUE ? "Private" : "Public", barejid);
1076 gpgme_key_t key = NULL;
1077 gpgme_error_t error;
1078
1079 gpgme_ctx_t ctx;
1080 error = gpgme_new(&ctx);
1081
1082 if (error) {
1083 log_error("OX - gpgme_new failed: %s %s", gpgme_strsource(error), gpgme_strerror(error));
1084 return NULL;
1085 }
1086
1087 error = gpgme_op_keylist_start(ctx, NULL, secret_only);
1088 if (error == GPG_ERR_NO_ERROR) {
1089 error = gpgme_op_keylist_next(ctx, &key);
1090 if (error != GPG_ERR_EOF && error != GPG_ERR_NO_ERROR) {
1091 log_error("OX: gpgme_op_keylist_next %s %s", gpgme_strsource(error), gpgme_strerror(error));
1092 return NULL;
1093 }
1094
1095 GString* xmppuri = g_string_new("xmpp:");
1096 g_string_append(xmppuri, barejid);
1097
1098 while (!error) {
1099 // Looking for XMPP URI UID
1100 gpgme_user_id_t uid = key->uids;
1101
1102 while (uid) {
1103 if (uid->name && strlen(uid->name) >= 10) {
1104 if (g_strcmp0(uid->name, xmppuri->str) == 0) {
1105 gpgme_release(ctx);
1106 return key;
1107 }
1108 }
1109 uid = uid->next;
1110 }
1111 gpgme_key_unref(key);
1112 error = gpgme_op_keylist_next(ctx, &key);
1113 }
1114 }
1115 gpgme_release(ctx);
1116
1117 return key;
1118 }
1119
1120 static gboolean
_ox_key_is_usable(gpgme_key_t key,const char * const barejid,gboolean secret)1121 _ox_key_is_usable(gpgme_key_t key, const char* const barejid, gboolean secret)
1122 {
1123 gboolean result = TRUE;
1124
1125 if (key->revoked || key->expired || key->disabled) {
1126 result = FALSE;
1127 }
1128
1129 return result;
1130 }
1131
1132 /*!
1133 * @brief XMPP-OX: Decrypt OX Message.
1134 *
1135 *
1136 *
1137 * @param base64 base64_encode OpenPGP message.
1138 *
1139 * @result decrypt XMPP OX Message NULL terminated C-String
1140 */
1141 char*
p_ox_gpg_decrypt(char * base64)1142 p_ox_gpg_decrypt(char* base64)
1143 {
1144 // if there is no private key avaibale,
1145 // we don't try do decrypt
1146 if(!ox_is_private_key_available(connection_get_barejid())) {
1147 return NULL;
1148 }
1149 setlocale(LC_ALL, "");
1150 gpgme_check_version(NULL);
1151 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
1152 gpgme_ctx_t ctx;
1153 gpgme_error_t error = gpgme_new(&ctx);
1154
1155 if (GPG_ERR_NO_ERROR != error) {
1156 printf("gpgme_new: %d\n", error);
1157 return NULL;
1158 }
1159
1160 error = gpgme_set_protocol(ctx, GPGME_PROTOCOL_OPENPGP);
1161 if (error != 0) {
1162 log_error("GpgME Error: %s", gpgme_strerror(error));
1163 }
1164
1165 gpgme_set_armor(ctx, 0);
1166 gpgme_set_textmode(ctx, 0);
1167 gpgme_set_offline(ctx, 1);
1168 gpgme_set_keylist_mode(ctx, GPGME_KEYLIST_MODE_LOCAL);
1169 if (error != 0) {
1170 log_error("GpgME Error: %s", gpgme_strerror(error));
1171 }
1172
1173 gpgme_data_t plain = NULL;
1174 gpgme_data_t cipher = NULL;
1175
1176 gsize s;
1177 guchar* encrypted = g_base64_decode(base64, &s);
1178 error = gpgme_data_new_from_mem(&cipher, (char*)encrypted, s, 0);
1179 if (error != 0) {
1180 log_error("GpgME Error gpgme_data_new_from_mem: %s", gpgme_strerror(error));
1181 return NULL;
1182 }
1183
1184 error = gpgme_data_new(&plain);
1185 if (error != 0) {
1186 log_error("GpgME Error: %s", gpgme_strerror(error));
1187 return NULL;
1188 }
1189
1190 error = gpgme_op_decrypt_verify(ctx, cipher, plain);
1191 if (error != 0) {
1192 log_error("GpgME Error gpgme_op_decrypt: %s", gpgme_strerror(error));
1193 error = gpgme_op_decrypt(ctx, cipher, plain);
1194 if (error != 0) {
1195 return NULL;
1196 }
1197 }
1198 size_t len;
1199 char* plain_str = gpgme_data_release_and_get_mem(plain, &len);
1200 char* result = malloc(len + 1);
1201 strcpy(result, plain_str);
1202 result[len] = '\0';
1203 return result;
1204 }
1205
1206 /*!
1207 * \brief Read public key from file.
1208 *
1209 * This function is used the read a public key from a file.
1210 *
1211 * This function is used to read a key and push it on PEP. There are some checks
1212 * in this function:
1213 *
1214 * Key is not
1215 * - gkey->revoked
1216 * - gkey->expired
1217 * - gkey->disabled
1218 * - gkey->invalid
1219 * - gkey->secret
1220 *
1221 * Only one key in the file.
1222 *
1223 * \param filename filename to read the file.
1224 * \param key result with base64 encode key or NULL
1225 * \param fp result with the fingerprint or NULL
1226 *
1227 */
1228
1229 void
p_ox_gpg_readkey(const char * const filename,char ** key,char ** fp)1230 p_ox_gpg_readkey(const char* const filename, char** key, char** fp)
1231 {
1232
1233 log_info("Read OpenPGP Key from file %s", filename);
1234
1235 GError* error = NULL;
1236 gchar* data = NULL;
1237 gsize size = -1;
1238
1239 gboolean success = g_file_get_contents(filename,
1240 &data,
1241 &size,
1242 &error);
1243 if (success) {
1244 setlocale(LC_ALL, "");
1245 gpgme_check_version(NULL);
1246 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
1247 gpgme_ctx_t ctx;
1248 gpgme_error_t error = gpgme_new(&ctx);
1249
1250 if (GPG_ERR_NO_ERROR != error) {
1251 log_error("Read OpenPGP key from file: gpgme_new failed: %s", gpgme_strerror(error));
1252 return;
1253 }
1254
1255 error = gpgme_set_protocol(ctx, GPGME_PROTOCOL_OPENPGP);
1256 if (error != GPG_ERR_NO_ERROR) {
1257 log_error("Read OpenPGP key from file: set GPGME_PROTOCOL_OPENPGP: %s", gpgme_strerror(error));
1258 return;
1259 }
1260
1261 gpgme_set_armor(ctx, 0);
1262 gpgme_set_textmode(ctx, 0);
1263 gpgme_set_offline(ctx, 1);
1264 gpgme_set_keylist_mode(ctx, GPGME_KEYLIST_MODE_LOCAL);
1265
1266 gpgme_data_t gpgme_data = NULL;
1267 error = gpgme_data_new(&gpgme_data);
1268 if (error != GPG_ERR_NO_ERROR) {
1269 log_error("Read OpenPGP key from file: gpgme_data_new %s", gpgme_strerror(error));
1270 return;
1271 }
1272
1273 error = gpgme_data_new_from_mem(&gpgme_data, (char*)data, size, 0);
1274 if (error != GPG_ERR_NO_ERROR) {
1275 log_error("Read OpenPGP key from file: gpgme_data_new_from_mem %s", gpgme_strerror(error));
1276 return;
1277 }
1278 error = gpgme_op_keylist_from_data_start(ctx, gpgme_data, 0);
1279 if (error != GPG_ERR_NO_ERROR) {
1280 log_error("Read OpenPGP key from file: gpgme_op_keylist_from_data_start %s", gpgme_strerror(error));
1281 return;
1282 }
1283 gpgme_key_t gkey;
1284 error = gpgme_op_keylist_next(ctx, &gkey);
1285 if (error != GPG_ERR_NO_ERROR) {
1286 log_error("Read OpenPGP key from file: gpgme_op_keylist_next %s", gpgme_strerror(error));
1287 return;
1288 }
1289
1290 gpgme_key_t end;
1291 error = gpgme_op_keylist_next(ctx, &end);
1292 if (error == GPG_ERR_NO_ERROR) {
1293 log_error("Read OpenPGP key from file: ambiguous key");
1294 return;
1295 }
1296
1297 if (gkey->revoked || gkey->expired || gkey->disabled || gkey->invalid || gkey->secret) {
1298 log_error("Read OpenPGP key from file: Key is not valid");
1299 return;
1300 }
1301
1302 gchar* keybase64 = g_base64_encode((const guchar*)data, size);
1303
1304 *key = strdup(keybase64);
1305 *fp = strdup(gkey->fpr);
1306 } else {
1307 log_error("Read OpenPGP key from file: Unable to read file: %s", error->message);
1308 }
1309 }
1310
1311 gboolean
p_ox_gpg_import(char * base64_public_key)1312 p_ox_gpg_import(char* base64_public_key)
1313 {
1314 gsize size = -1;
1315 guchar* key = g_base64_decode(base64_public_key, &size);
1316
1317 setlocale(LC_ALL, "");
1318 gpgme_check_version(NULL);
1319 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
1320 gpgme_ctx_t ctx;
1321 gpgme_error_t error = gpgme_new(&ctx);
1322
1323 if (GPG_ERR_NO_ERROR != error) {
1324 log_error("Read OpenPGP key from file: gpgme_new failed: %s", gpgme_strerror(error));
1325 return FALSE;
1326 }
1327
1328 error = gpgme_set_protocol(ctx, GPGME_PROTOCOL_OPENPGP);
1329 if (error != GPG_ERR_NO_ERROR) {
1330 log_error("Read OpenPGP key from file: set GPGME_PROTOCOL_OPENPGP: %s", gpgme_strerror(error));
1331 return FALSE;
1332 }
1333
1334 gpgme_set_armor(ctx, 0);
1335 gpgme_set_textmode(ctx, 0);
1336 gpgme_set_offline(ctx, 1);
1337 gpgme_set_keylist_mode(ctx, GPGME_KEYLIST_MODE_LOCAL);
1338
1339 gpgme_data_t gpgme_data = NULL;
1340 error = gpgme_data_new(&gpgme_data);
1341 if (error != GPG_ERR_NO_ERROR) {
1342 log_error("Read OpenPGP key from file: gpgme_data_new %s", gpgme_strerror(error));
1343 return FALSE;
1344 }
1345
1346 gpgme_data_new_from_mem(&gpgme_data, (gchar*)key, size, 0);
1347 error = gpgme_op_import(ctx, gpgme_data);
1348 if (error != GPG_ERR_NO_ERROR) {
1349 log_error("Failed to import key");
1350 }
1351
1352 return TRUE;
1353 }
1354