1 /*
2  * pgp.c        -- PGP utility functions
3  *
4  * Copyright (C) 2006-2015 Mikael Berthe <mikael@lilotux.net>
5  * Some parts inspired by centericq (impgp.cc)
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or (at
10  * your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 
23 #ifdef HAVE_GPGME
24 
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <locale.h>
29 #include <sys/mman.h>
30 #include <glib.h>
31 
32 #include "pgp.h"
33 #include "settings.h"
34 #include "utils.h"
35 #include "logprint.h"
36 
37 #define MIN_GPGME_VERSION "1.1.0"
38 
39 static struct gpg_struct
40 {
41   int   enabled;
42   int   version1;
43   char *private_key;
44   char *passphrase;
45 } gpg;
46 
47 
48 //  gpg_init(priv_key, passphrase)
49 // Initialize the GPG sub-systems.  This function must be invoked early.
50 // Note: priv_key & passphrase are optional, they can be set later.
51 // This function returns 0 if gpgme is available and initialized;
52 // if not it returns the gpgme error code.
gpg_init(const char * priv_key,const char * passphrase)53 int gpg_init(const char *priv_key, const char *passphrase)
54 {
55   gpgme_error_t err;
56 
57   gpgme_ctx_t ctx;
58   gpgme_engine_info_t info;
59   const char *gpg_path, *gpg_home;
60 
61   // Check for version and OpenPGP protocol support.
62   if (!gpgme_check_version(MIN_GPGME_VERSION)) {
63     scr_LogPrint(LPRINT_LOGNORM,
64                  "GPGME initialization error: Bad library version");
65     return -1;
66   }
67 
68   err = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
69   if (err) {
70     scr_LogPrint(LPRINT_LOGNORM|LPRINT_NOTUTF8,
71                  "GPGME initialization error: %s", gpgme_strerror(err));
72     return err;
73   }
74 
75   // Set the locale information.
76   gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
77   gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
78 
79   // The path to the gpg binary can be specified in order to force
80   // version 1, for example.
81   gpg_path = settings_opt_get("gpg_path");
82   gpg_home = settings_opt_get("gpg_home");
83   if (gpg_path || gpg_home) {
84     char *xp_gpg_home = expand_filename(gpg_home);
85     err = gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP, gpg_path, xp_gpg_home);
86     g_free(xp_gpg_home);
87     if (err) return -1;
88   }
89 
90   // Store private data.
91   gpg_set_private_key(priv_key);
92   gpg_set_passphrase(passphrase);
93 
94   err = gpgme_new(&ctx);
95   if (err) return -1;
96 
97   // Check OpenPGP engine version; with version 2+ the agent is mandatory
98   // and we do not manage the passphrase.
99   gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
100   if (err) return -1;
101 
102   err = gpgme_get_engine_info(&info);
103   if (!err) {
104     while (info && info->protocol != gpgme_get_protocol(ctx))
105       info = info->next;
106 
107     if (info && info->version) {
108       if (!strncmp(info->version, "1.", 2))
109         gpg.version1 = TRUE;
110       scr_log_print(LPRINT_DEBUG, "GPGME: Engine version is '%s'.",
111                     info->version);
112     }
113   }
114 
115   gpgme_release(ctx);
116   gpg.enabled = 1;
117   return 0;
118 }
119 
120 //  gpg_is_version1()
121 // Return TRUE if the GnuPG OpenPGP engine version is 1.x
gpg_is_version1(void)122 int gpg_is_version1(void)
123 {
124   return gpg.version1;
125 }
126 
127 //  gpg_terminate()
128 // Destroy data and free memory.
gpg_terminate(void)129 void gpg_terminate(void)
130 {
131   gpg.enabled = 0;
132   gpg_set_passphrase(NULL);
133   gpg_set_private_key(NULL);
134 }
135 
136 //  gpg_set_passphrase(passphrase)
137 // Set the current passphrase (use NULL to erase it).
gpg_set_passphrase(const char * passphrase)138 void gpg_set_passphrase(const char *passphrase)
139 {
140   // Remove current passphrase
141   if (gpg.passphrase) {
142     ssize_t len = strlen(gpg.passphrase);
143     memset(gpg.passphrase, 0, len);
144     munlock(gpg.passphrase, len);
145     g_free(gpg.passphrase);
146   }
147   if (passphrase) {
148     gpg.passphrase = g_strdup(passphrase);
149     mlock(gpg.passphrase, strlen(gpg.passphrase));
150   } else {
151     gpg.passphrase = NULL;
152   }
153 }
154 
155 //  gpg_set_private_key(keyid)
156 // Set the current private key id (use NULL to unset it).
gpg_set_private_key(const char * priv_keyid)157 void gpg_set_private_key(const char *priv_keyid)
158 {
159   g_free(gpg.private_key);
160   if (priv_keyid)
161     gpg.private_key = g_strdup(priv_keyid);
162   else
163     gpg.private_key = NULL;
164 }
165 
166 //  gpg_get_private_key_id()
167 // Return the current private key id (static string).
gpg_get_private_key_id(void)168 const char *gpg_get_private_key_id(void)
169 {
170   return gpg.private_key;
171 }
172 
173 //  strip_header_footer(data)
174 // Remove PGP header & footer from data.
175 // Return a new string, or NULL.
176 // The string must be freed by the caller with g_free() when no longer needed.
strip_header_footer(const char * data)177 static char *strip_header_footer(const char *data)
178 {
179   char *p, *q;
180 
181   if (!data)
182     return NULL;
183 
184   // p: beginning of real data
185   // q: end of real data
186 
187   // Strip header (to the first empty line)
188   p = strstr(data, "\n\n");
189   if (!p)
190     return g_strdup(data);
191 
192   // Strip footer
193   // We want to remove the last lines, until the line beginning with a '-'
194   p += 2;
195   for (q = p ; *q; q++) ;
196   // (q is at the end of data now)
197   for (q--; q > p && (*q != '\n' || *(q+1) != '-'); q--) ;
198 
199   if (q <= p)
200     return NULL; // Shouldn't happen...
201 
202   return g_strndup(p, q-p);
203 }
204 
205 // GCC ignores casts to void, thus we need to hack around that
ignore(void * x)206 static inline void ignore(void*x) {}
207 
208 //  passphrase_cb()
209 // GPGME passphrase callback function.
passphrase_cb(void * hook,const char * uid_hint,const char * passphrase_info,int prev_was_bad,int fd)210 static gpgme_error_t passphrase_cb(void *hook, const char *uid_hint,
211                        const char *passphrase_info, int prev_was_bad, int fd)
212 {
213   ssize_t len;
214 
215   // Abort if we do not have the password.
216   if (!gpg.passphrase) {
217     ignore((void*)write(fd, "\n", 1)); // We have an error anyway, thus it does
218                                        // not matter if we fail again.
219     return gpg_error(GPG_ERR_CANCELED);
220   }
221 
222   // Write the passphrase to the file descriptor.
223   len = strlen(gpg.passphrase);
224   if (write(fd, gpg.passphrase, len) != len)
225     return gpg_error(GPG_ERR_CANCELED);
226   if (write(fd, "\n", 1) != 1)
227     return gpg_error(GPG_ERR_CANCELED);
228 
229   return 0; // Success
230 }
231 
232 //  gpg_verify(gpg_data, text, *sigsum)
233 // Verify that gpg_data is a correct signature for text.
234 // Return the key id (or fingerprint), and set *sigsum to
235 // the gpgme signature summary value.
236 // The returned string must be freed with g_free() after use.
gpg_verify(const char * gpg_data,const char * text,gpgme_sigsum_t * sigsum)237 char *gpg_verify(const char *gpg_data, const char *text,
238                  gpgme_sigsum_t *sigsum)
239 {
240   gpgme_ctx_t ctx;
241   gpgme_data_t data_sign, data_text;
242   char *data;
243   char *verified_key = NULL;
244   gpgme_key_t key;
245   gpgme_error_t err;
246   const char prefix[] = "-----BEGIN PGP SIGNATURE-----\n\n";
247   const char suffix[] = "\n-----END PGP SIGNATURE-----\n";
248 
249   // Reset the summary.
250   *sigsum = 0;
251 
252   if (!gpg.enabled)
253     return NULL;
254 
255   err = gpgme_new(&ctx);
256   if (err) {
257     scr_LogPrint(LPRINT_LOGNORM|LPRINT_NOTUTF8,
258                  "GPGME error: %s", gpgme_strerror(err));
259     return NULL;
260   }
261 
262   gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
263 
264   // Surround the given data with the prefix & suffix
265   data = g_new(char, sizeof(prefix) + sizeof(suffix) + strlen(gpg_data));
266   strcpy(data, prefix);
267   strcat(data, gpg_data);
268   strcat(data, suffix);
269 
270   err = gpgme_data_new_from_mem(&data_sign, data, strlen(data), 0);
271   if (!err) {
272     err = gpgme_data_new_from_mem(&data_text, text, strlen(text), 0);
273     if (!err) {
274       err = gpgme_op_verify(ctx, data_sign, data_text, 0);
275       if (!err) {
276         gpgme_verify_result_t vr = gpgme_op_verify_result(ctx);
277         if (vr && vr->signatures) {
278             gpgme_signature_t s = NULL;
279             // check all signatures and stop if the first could be verified
280             for (s = vr->signatures; s && !verified_key; s = s->next) {
281                 // Found the fingerprint.  Let's try to get the key id.
282                 if (NULL != s->fpr) {
283                     if (!gpgme_get_key(ctx, s->fpr, &key, 0)) {
284                         if (key) {
285                             verified_key = g_strdup(key->subkeys->keyid);
286                             gpgme_key_release(key);
287                         }
288                     }
289                 }
290                 *sigsum = s->summary;
291                 // For some reason summary could be 0 when status is 0 too,
292                 // which means the signature is valid...
293                 if ((!*sigsum) && (!s->status))
294                     *sigsum = GPGME_SIGSUM_GREEN;
295             }
296         }
297       }
298       gpgme_data_release(data_text);
299     }
300     gpgme_data_release(data_sign);
301   }
302   if (err)
303     scr_LogPrint(LPRINT_LOGNORM|LPRINT_NOTUTF8,
304                  "GPGME verification error: %s", gpgme_strerror(err));
305   gpgme_release(ctx);
306   g_free(data);
307   return verified_key;
308 }
309 
310 //  gpg_sign(gpg_data)
311 // Return a signature of gpg_data (or NULL).
312 // The returned string must be freed with g_free() after use.
gpg_sign(const char * gpg_data)313 char *gpg_sign(const char *gpg_data)
314 {
315   gpgme_ctx_t ctx;
316   gpgme_data_t in, out;
317   char *signed_data = NULL;
318   size_t nread;
319   gpgme_key_t key;
320   gpgme_error_t err;
321 
322   if (!gpg.enabled || !gpg.private_key)
323     return NULL;
324 
325   err = gpgme_new(&ctx);
326   if (err) {
327     scr_LogPrint(LPRINT_LOGNORM|LPRINT_NOTUTF8,
328                  "GPGME error: %s", gpgme_strerror(err));
329     return NULL;
330   }
331 
332   gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
333   gpgme_set_textmode(ctx, 0);
334   gpgme_set_armor(ctx, 1);
335 
336   if (gpg.version1) {
337     // GPG_AGENT_INFO isn't used by GnuPG version 2+
338     char *p = getenv("GPG_AGENT_INFO");
339     if (!(p && strchr(p, ':')))
340       gpgme_set_passphrase_cb(ctx, passphrase_cb, 0);
341   }
342 
343   err = gpgme_get_key(ctx, gpg.private_key, &key, 1);
344   if (err || !key) {
345     scr_LogPrint(LPRINT_LOGNORM, "GPGME error: private key not found");
346     gpgme_release(ctx);
347     return NULL;
348   }
349 
350   gpgme_signers_clear(ctx);
351   gpgme_signers_add(ctx, key);
352   gpgme_key_release(key);
353   err = gpgme_data_new_from_mem(&in, gpg_data, strlen(gpg_data), 0);
354   if (!err) {
355     err = gpgme_data_new(&out);
356     if (!err) {
357       err = gpgme_op_sign(ctx, in, out, GPGME_SIG_MODE_DETACH);
358       if (err) {
359         gpgme_data_release(out);
360       } else {
361         signed_data = gpgme_data_release_and_get_mem(out, &nread);
362         if (signed_data) {
363           // We need to add a trailing NULL
364           char *dd = g_strndup(signed_data, nread);
365           free(signed_data);
366           signed_data = strip_header_footer(dd);
367           g_free(dd);
368         }
369       }
370     }
371     gpgme_data_release(in);
372   }
373   if (err && err != GPG_ERR_CANCELED)
374     scr_LogPrint(LPRINT_LOGNORM|LPRINT_NOTUTF8,
375                  "GPGME signature error: %s", gpgme_strerror(err));
376   gpgme_release(ctx);
377   return signed_data;
378 }
379 
380 //  gpg_decrypt(gpg_data)
381 // Return decrypted gpg_data (or NULL).
382 // The returned string must be freed with g_free() after use.
gpg_decrypt(const char * gpg_data)383 char *gpg_decrypt(const char *gpg_data)
384 {
385   gpgme_ctx_t ctx;
386   gpgme_data_t in, out;
387   char *data;
388   char *decrypted_data = NULL;
389   size_t nread;
390   gpgme_error_t err;
391   const char prefix[] = "-----BEGIN PGP MESSAGE-----\n\n";
392   const char suffix[] = "\n-----END PGP MESSAGE-----\n";
393 
394   if (!gpg.enabled)
395     return NULL;
396 
397   err = gpgme_new(&ctx);
398   if (err) {
399     scr_LogPrint(LPRINT_LOGNORM|LPRINT_NOTUTF8,
400                  "GPGME error: %s", gpgme_strerror(err));
401     return NULL;
402   }
403 
404   gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
405 
406   if (gpg.version1) {
407     // GPG_AGENT_INFO isn't used by GnuPG version 2+
408     char *p = getenv("GPG_AGENT_INFO");
409     if (!(p && strchr(p, ':')))
410       gpgme_set_passphrase_cb(ctx, passphrase_cb, 0);
411   }
412 
413   // Surround the given data with the prefix & suffix
414   data = g_new(char, sizeof(prefix) + sizeof(suffix) + strlen(gpg_data));
415   strcpy(data, prefix);
416   strcat(data, gpg_data);
417   strcat(data, suffix);
418 
419   err = gpgme_data_new_from_mem(&in, data, strlen(data), 0);
420   if (!err) {
421     err = gpgme_data_new(&out);
422     if (!err) {
423       err = gpgme_op_decrypt(ctx, in, out);
424       if (err) {
425         gpgme_data_release(out);
426       } else {
427         decrypted_data = gpgme_data_release_and_get_mem(out, &nread);
428         if (decrypted_data) {
429           // We need to add a trailing NULL
430           char *dd = g_strndup(decrypted_data, nread);
431           free(decrypted_data);
432           decrypted_data = dd;
433         }
434       }
435     }
436     gpgme_data_release(in);
437   }
438   if (err && err != GPG_ERR_CANCELED)
439     scr_LogPrint(LPRINT_LOGNORM|LPRINT_NOTUTF8,
440                  "GPGME decryption error: %s", gpgme_strerror(err));
441   gpgme_release(ctx);
442   g_free(data);
443   return decrypted_data;
444 }
445 
446 //  gpg_encrypt(gpg_data, keyids[], n)
447 // Return encrypted gpg_data with the n keys from the keyids array (or NULL).
448 // The returned string must be freed with g_free() after use.
gpg_encrypt(const char * gpg_data,const char * keyids[],size_t nkeys)449 char *gpg_encrypt(const char *gpg_data, const char *keyids[], size_t nkeys)
450 {
451   gpgme_ctx_t ctx;
452   gpgme_data_t in, out;
453   char *encrypted_data = NULL, *edata;
454   size_t nread;
455   gpgme_key_t *keys;
456   gpgme_error_t err;
457   unsigned i;
458 
459   if (!gpg.enabled)
460     return NULL;
461 
462   if (!keyids || !nkeys) {
463     return NULL;
464   }
465 
466   err = gpgme_new(&ctx);
467   if (err) {
468     scr_LogPrint(LPRINT_LOGNORM|LPRINT_NOTUTF8,
469                  "GPGME error: %s", gpgme_strerror(err));
470     return NULL;
471   }
472 
473   gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
474   gpgme_set_textmode(ctx, 0);
475   gpgme_set_armor(ctx, 1);
476 
477   keys = g_new0(gpgme_key_t, 1+nkeys);
478   if (!keys) {
479     gpgme_release(ctx);
480     return NULL;
481   }
482 
483   for (i = 0; i < nkeys; i++) {
484     err = gpgme_get_key(ctx, keyids[i], &keys[i], 0);
485     if (err || !keys[i]) {
486       scr_LogPrint(LPRINT_LOGNORM, "GPGME encryption error: cannot use key %s",
487                    keyids[i]);
488       // We need to have err not null to ensure we won't try to encrypt
489       // without this key.
490       if (!err) err = GPG_ERR_UNKNOWN_ERRNO;
491       break;
492     }
493   }
494 
495   if (!err) {
496     err = gpgme_data_new_from_mem(&in, gpg_data, strlen(gpg_data), 0);
497     if (!err) {
498       err = gpgme_data_new(&out);
499       if (!err) {
500         err = gpgme_op_encrypt(ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
501         if (err) {
502           gpgme_data_release(out);
503         } else {
504           encrypted_data = gpgme_data_release_and_get_mem(out, &nread);
505           if (encrypted_data) {
506             // We need to add a trailing NULL
507             char *dd = g_strndup(encrypted_data, nread);
508             free(encrypted_data);
509             encrypted_data = dd;
510           }
511         }
512       }
513       gpgme_data_release(in);
514     }
515 
516     if (err && err != GPG_ERR_CANCELED) {
517       scr_LogPrint(LPRINT_LOGNORM|LPRINT_NOTUTF8,
518                    "GPGME encryption error: %s", gpgme_strerror(err));
519     }
520   }
521 
522   for (i = 0; keys[i]; i++)
523     gpgme_key_release(keys[i]);
524   g_free(keys);
525   gpgme_release(ctx);
526   edata = strip_header_footer(encrypted_data);
527   if (encrypted_data)
528     free(encrypted_data);
529   return edata;
530 }
531 
532 //  gpg_test_passphrase()
533 // Test the current gpg.passphrase with gpg.private_key.
534 // If the test doesn't succeed, the passphrase is cleared and a non-null
535 // value is returned.
gpg_test_passphrase(void)536 int gpg_test_passphrase(void)
537 {
538   char *s;
539 
540   if (!gpg.private_key)
541     return -1; // No private key...
542 
543   s = gpg_sign("test");
544   if (s) {
545     free(s);
546     return 0; // Ok, test successful
547   }
548   // The passphrase is wrong (if provided)
549   gpg_set_passphrase(NULL);
550   return -1;
551 }
552 
gpg_enabled(void)553 int gpg_enabled(void)
554 {
555   return gpg.enabled;
556 }
557 
558 #else  /* not HAVE_GPGME */
559 
gpg_enabled(void)560 int gpg_enabled(void)
561 {
562   return 0;
563 }
564 
565 #endif /* HAVE_GPGME */
566 
567 /* vim: set et cindent cinoptions=>2\:2(0 ts=2 sw=2:  For Vim users... */
568