Branch data Line data Source code
1 : : /**
2 : : * \file lib/gpgme_funcs.c
3 : : *
4 : : * \brief gpgme-related functions for GPG encryptions support in libfko.
5 : : */
6 : :
7 : : /* Fwknop is developed primarily by the people listed in the file 'AUTHORS'.
8 : : * Copyright (C) 2009-2015 fwknop developers and contributors. For a full
9 : : * list of contributors, see the file 'CREDITS'.
10 : : *
11 : : * License (GNU General Public License):
12 : : *
13 : : * This program is free software; you can redistribute it and/or
14 : : * modify it under the terms of the GNU General Public License
15 : : * as published by the Free Software Foundation; either version 2
16 : : * of the License, or (at your option) any later version.
17 : : *
18 : : * This program is distributed in the hope that it will be useful,
19 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 : : * GNU General Public License for more details.
22 : : *
23 : : * You should have received a copy of the GNU General Public License
24 : : * along with this program; if not, write to the Free Software
25 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 : : * USA
27 : : *
28 : : *****************************************************************************
29 : : */
30 : :
31 : : #include "fko_common.h"
32 : : #include "fko.h"
33 : :
34 : : #if HAVE_LIBGPGME
35 : : #include "gpgme_funcs.h"
36 : :
37 : : int
38 : 309 : init_gpgme(fko_ctx_t fko_ctx)
39 : : {
40 : : gpgme_error_t err;
41 : :
42 : : /* If we already have a context, we are done.
43 : : */
44 [ + + ]: 309 : if(fko_ctx->have_gpgme_context)
45 : : return(FKO_SUCCESS);
46 : :
47 : : /* Because the gpgme manual says you should.
48 : : */
49 : 154 : gpgme_check_version(NULL);
50 : :
51 : : /* Check for OpenPGP support
52 : : */
53 : 154 : err = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
54 [ - + ]: 154 : if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
55 : : {
56 : : /* GPG engine is not available.
57 : : */
58 : 0 : fko_ctx->gpg_err = err;
59 : 0 : return(FKO_ERROR_GPGME_NO_OPENPGP);
60 : : }
61 : :
62 : : /* Extract the current gpgme engine information.
63 : : */
64 [ + + ]: 154 : gpgme_set_engine_info(
65 : : GPGME_PROTOCOL_OpenPGP,
66 : 154 : (fko_ctx->gpg_exe != NULL) ? fko_ctx->gpg_exe : GPG_EXE,
67 : 154 : fko_ctx->gpg_home_dir /* If this is NULL, the default is used */
68 : : );
69 : :
70 : : /* Create our gpgme context
71 : : */
72 : 154 : err = gpgme_new(&(fko_ctx->gpg_ctx));
73 [ - + ]: 154 : if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
74 : : {
75 : 0 : fko_ctx->gpg_err = err;
76 : 0 : return(FKO_ERROR_GPGME_CONTEXT);
77 : : }
78 : :
79 : 154 : fko_ctx->have_gpgme_context = 1;
80 : :
81 : 154 : return(FKO_SUCCESS);
82 : : }
83 : :
84 : : /* Callback function that supplies the password when gpgme needs it.
85 : : */
86 : : gpgme_error_t
87 : 65 : my_passphrase_cb(
88 : : void *pw, const char *uid_hint, const char *passphrase_info,
89 : : int prev_was_bad, int fd)
90 : : {
91 : : /* We only need to try once as it is fed by the program
92 : : * (for now --DSS).
93 : : */
94 [ + - ]: 65 : if(prev_was_bad)
95 : : return(GPG_ERR_CANCELED);
96 : :
97 [ + - ]: 65 : if(write(fd, (const char*)pw, strlen((const char*)pw))
98 : 65 : != strlen((const char*)pw))
99 : : return(GPG_ERR_SYSTEM_ERROR); /* Must be a GPG error, but which one? */
100 : :
101 [ + - ]: 65 : if(write(fd, "\n", 1) != 1)
102 : : return(GPG_ERR_SYSTEM_ERROR); /* Must be a GPG error, but which one? */
103 : :
104 : 65 : return 0;
105 : : }
106 : :
107 : : /* Verify gpg signatures in a verify_result set.
108 : : */
109 : : static int
110 : 120 : process_sigs(fko_ctx_t fko_ctx, gpgme_verify_result_t vres)
111 : : {
112 : 60 : unsigned int sig_cnt = 0;
113 : 60 : gpgme_signature_t sig = vres->signatures;
114 : : fko_gpg_sig_t fgs;
115 : :
116 : : /* only want to see one signature (for now).
117 : : */
118 [ + - ]: 60 : if(!sig)
119 : : return(FKO_ERROR_GPGME_NO_SIGNATURE);
120 : :
121 : : /* Iterate over the sigs and store the info we are interested in
122 : : * to the context.
123 : : *
124 : : * NOTE: At present, we support only a single signature. However,
125 : : * that may change in a future release. We go a head and
126 : : * grab all signatures even though we will only use the first
127 : : * one. --DSS
128 : : */
129 [ + + ]: 120 : while(sig != NULL)
130 : : {
131 : 60 : fgs = calloc(1, sizeof(struct fko_gpg_sig));
132 [ + - ]: 60 : if(fgs == NULL)
133 : : return(FKO_ERROR_MEMORY_ALLOCATION);
134 : :
135 : : /* Grab the summary and status values.
136 : : */
137 : 60 : fgs->summary = sig->summary;
138 : 60 : fgs->status = sig->status;
139 : 60 : fgs->validity = sig->validity;
140 : :
141 : : /* Grab the signature fingerprint.
142 : : */
143 [ + - ]: 60 : if(sig->fpr != NULL)
144 : : {
145 : 60 : fgs->fpr = strdup(sig->fpr);
146 [ - + ]: 60 : if(fgs->fpr == NULL)
147 : : {
148 : 0 : free(fgs);
149 : : return(FKO_ERROR_MEMORY_ALLOCATION);
150 : : }
151 : : }
152 : :
153 [ + - ]: 60 : if(sig_cnt == 0)
154 : 60 : fko_ctx->gpg_sigs = fgs;
155 : : else
156 : 0 : fko_ctx->gpg_sigs->next = fgs;
157 : :
158 : 60 : sig_cnt++;
159 : 60 : sig = sig->next;
160 : : }
161 : :
162 : : /* If we are ignoring bad signatures, return success here.
163 : : */
164 [ + - ]: 60 : if(fko_ctx->ignore_gpg_sig_error != 0)
165 : : return(FKO_SUCCESS);
166 : :
167 : : /* Otherwise, we check them here and respond accordingly.
168 : : */
169 : 60 : fgs = fko_ctx->gpg_sigs;
170 : :
171 [ + - ][ - + ]: 60 : if(fgs->status != GPG_ERR_NO_ERROR || fgs->validity < 3) {
172 : 0 : fko_ctx->gpg_err = fgs->status;
173 : :
174 : : return(FKO_ERROR_GPGME_BAD_SIGNATURE);
175 : : }
176 : :
177 : : return(FKO_SUCCESS);
178 : : }
179 : :
180 : : /* Get the GPG key for the given name or ID.
181 : : */
182 : : int
183 : 157 : get_gpg_key(fko_ctx_t fko_ctx, gpgme_key_t *mykey, const int signer)
184 : : {
185 : : int res;
186 : : const char *name;
187 : :
188 : 157 : gpgme_ctx_t list_ctx = NULL;
189 : 157 : gpgme_key_t key = NULL;
190 : 157 : gpgme_key_t key2 = NULL;
191 : : gpgme_error_t err;
192 : :
193 : : /* Create a gpgme context for the list
194 : : */
195 : : /* Initialize gpgme
196 : : */
197 : 157 : res = init_gpgme(fko_ctx);
198 [ - + ]: 157 : if(res != FKO_SUCCESS)
199 : : {
200 [ # # ]: 0 : if(signer)
201 : : return(FKO_ERROR_GPGME_CONTEXT_SIGNER_KEY);
202 : : else
203 : 0 : return(FKO_ERROR_GPGME_CONTEXT_RECIPIENT_KEY);
204 : : }
205 : :
206 : 157 : list_ctx = fko_ctx->gpg_ctx;
207 : :
208 [ + + ]: 157 : if(signer)
209 : 78 : name = fko_ctx->gpg_signer;
210 : : else
211 : 79 : name = fko_ctx->gpg_recipient;
212 : :
213 : 157 : err = gpgme_op_keylist_start(list_ctx, name, signer);
214 [ - + ]: 157 : if (err)
215 : : {
216 : 0 : gpgme_release(list_ctx);
217 : :
218 : 0 : fko_ctx->gpg_err = err;
219 : :
220 [ # # ]: 0 : if(signer)
221 : : return(FKO_ERROR_GPGME_SIGNER_KEYLIST_START);
222 : : else
223 : 0 : return(FKO_ERROR_GPGME_RECIPIENT_KEYLIST_START);
224 : : }
225 : :
226 : : /* Grab the first key in the list (we hope it is the only one).
227 : : */
228 : 157 : err = gpgme_op_keylist_next(list_ctx, &key);
229 [ + + ]: 157 : if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
230 : : {
231 : : /* Key not found
232 : : */
233 : 2 : fko_ctx->gpg_err = err;
234 : :
235 [ + + ]: 2 : if(signer)
236 : : return(FKO_ERROR_GPGME_SIGNER_KEY_NOT_FOUND);
237 : : else
238 : 1 : return(FKO_ERROR_GPGME_RECIPIENT_KEY_NOT_FOUND);
239 : : }
240 : :
241 : : /* We try to get the next key match. If we do, then the name is
242 : : * ambiguous, so we return an error.
243 : : */
244 : 155 : err = gpgme_op_keylist_next(list_ctx, &key2);
245 [ - + ]: 155 : if(gpg_err_code(err) == GPG_ERR_NO_ERROR) /* Note: look for NO error */
246 : : {
247 : : /* Ambiguous specfication of key
248 : : */
249 : 0 : gpgme_key_unref(key);
250 : 0 : gpgme_key_unref(key2);
251 : :
252 : 0 : fko_ctx->gpg_err = err;
253 : :
254 [ # # ]: 0 : if(signer)
255 : : return(FKO_ERROR_GPGME_SIGNER_KEY_AMBIGUOUS);
256 : : else
257 : 0 : return(FKO_ERROR_GPGME_RECIPIENT_KEY_AMBIGUOUS);
258 : : }
259 : :
260 : 155 : gpgme_op_keylist_end(list_ctx);
261 : :
262 : 155 : gpgme_key_unref(key2);
263 : :
264 : 155 : *mykey = key;
265 : :
266 : 155 : return(FKO_SUCCESS);
267 : : }
268 : :
269 : : /* The main GPG encryption routine for libfko.
270 : : */
271 : : int
272 : 77 : gpgme_encrypt(fko_ctx_t fko_ctx, unsigned char *indata, size_t in_len,
273 : : const char *pw, unsigned char **out, size_t *out_len)
274 : : {
275 : : char *tmp_buf;
276 : : int res;
277 : :
278 : 77 : gpgme_ctx_t gpg_ctx = NULL;
279 : 77 : gpgme_data_t cipher = NULL;
280 : 77 : gpgme_data_t plaintext = NULL;
281 : 77 : gpgme_key_t key[2] = { NULL, NULL };
282 : : gpgme_error_t err;
283 : :
284 : : /* Initialize gpgme
285 : : */
286 : 77 : res = init_gpgme(fko_ctx);
287 [ + - ]: 77 : if(res != FKO_SUCCESS)
288 : : return(res);
289 : :
290 : 77 : gpg_ctx = fko_ctx->gpg_ctx;
291 : :
292 : : /* Initialize the plaintext data (place into gpgme_data object)
293 : : */
294 : 77 : err = gpgme_data_new_from_mem(&plaintext, (char*)indata, in_len, 1);
295 [ - + ]: 77 : if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
296 : : {
297 : 0 : gpgme_release(gpg_ctx);
298 : 0 : fko_ctx->gpg_ctx = NULL;
299 : 0 : fko_ctx->gpg_err = err;
300 : :
301 : 0 : return(FKO_ERROR_GPGME_PLAINTEXT_DATA_OBJ);
302 : : }
303 : :
304 : : /* Set protocol
305 : : */
306 : 77 : err = gpgme_set_protocol(gpg_ctx, GPGME_PROTOCOL_OpenPGP);
307 [ - + ]: 77 : if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
308 : : {
309 : 0 : gpgme_data_release(plaintext);
310 : 0 : gpgme_release(gpg_ctx);
311 : 0 : fko_ctx->gpg_ctx = NULL;
312 : :
313 : 0 : fko_ctx->gpg_err = err;
314 : :
315 : 0 : return(FKO_ERROR_GPGME_SET_PROTOCOL);
316 : : }
317 : :
318 : : /* Set ascii-armor off (we will be base64-encoding the encrypted data
319 : : * ourselves.
320 : : */
321 : 77 : gpgme_set_armor(gpg_ctx, 0);
322 : :
323 : : /* The gpgme_encrypt.... functions take a recipient key array, so we add
324 : : * our single key here.
325 : : */
326 : 77 : key[0] = fko_ctx->recipient_key;
327 : :
328 : : /* Create the buffer for our encrypted data.
329 : : */
330 : 77 : err = gpgme_data_new(&cipher);
331 [ - + ]: 77 : if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
332 : : {
333 : 0 : gpgme_data_release(plaintext);
334 : 0 : gpgme_release(gpg_ctx);
335 : 0 : fko_ctx->gpg_ctx = NULL;
336 : :
337 : 0 : fko_ctx->gpg_err = err;
338 : :
339 : 0 : return(FKO_ERROR_GPGME_CIPHER_DATA_OBJ);
340 : : }
341 : :
342 : : /* Here we add the signer to the gpgme context if there is one.
343 : : */
344 [ + - ]: 77 : if(fko_ctx->gpg_signer != NULL) {
345 : 77 : gpgme_signers_clear(gpg_ctx);
346 : 77 : err = gpgme_signers_add(gpg_ctx, fko_ctx->signer_key);
347 [ - + ]: 77 : if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
348 : : {
349 : 0 : gpgme_data_release(plaintext);
350 : 0 : gpgme_data_release(cipher);
351 : 0 : gpgme_release(gpg_ctx);
352 : 0 : fko_ctx->gpg_ctx = NULL;
353 : :
354 : 0 : fko_ctx->gpg_err = err;
355 : :
356 : 0 : return(FKO_ERROR_GPGME_ADD_SIGNER);
357 : : }
358 : : }
359 : :
360 : : /* Set the passphrase callback.
361 : : */
362 : 77 : gpgme_set_passphrase_cb(gpg_ctx, my_passphrase_cb, (void*)pw);
363 : :
364 : : /* Encrypt and sign (if a sig was provided) the SPA data.
365 : : */
366 [ - + ]: 77 : if(fko_ctx->gpg_signer == NULL)
367 : 0 : err = gpgme_op_encrypt(
368 : : gpg_ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, cipher
369 : : );
370 : : else
371 : 77 : err = gpgme_op_encrypt_sign(
372 : : gpg_ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, cipher
373 : : );
374 : :
375 [ - + ]: 77 : if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
376 : : {
377 : 0 : gpgme_data_release(plaintext);
378 : 0 : gpgme_data_release(cipher);
379 : 0 : gpgme_release(gpg_ctx);
380 : 0 : fko_ctx->gpg_ctx = NULL;
381 : :
382 : 0 : fko_ctx->gpg_err = err;
383 : :
384 [ # # ]: 0 : if(gpgme_err_code(err) == GPG_ERR_CANCELED)
385 : : return(FKO_ERROR_GPGME_BAD_PASSPHRASE);
386 : :
387 : 0 : return(FKO_ERROR_GPGME_ENCRYPT_SIGN);
388 : : }
389 : :
390 : : /* Done with the plaintext.
391 : : */
392 : 77 : gpgme_data_release(plaintext);
393 : :
394 : : /* Get the encrypted data and its length from the gpgme data object.
395 : : * BTW, this does free the memory used by cipher.
396 : : */
397 : 77 : tmp_buf = gpgme_data_release_and_get_mem(cipher, out_len);
398 : :
399 : 77 : *out = calloc(1, *out_len); /* This is freed upon fko_ctx destruction. */
400 [ + - ]: 77 : if(*out == NULL)
401 : : res = FKO_ERROR_MEMORY_ALLOCATION;
402 : : else
403 : : {
404 : 77 : memcpy(*out, tmp_buf, *out_len);
405 : 77 : res = FKO_SUCCESS;
406 : : }
407 : :
408 : 77 : gpgme_free(tmp_buf);
409 : :
410 : 77 : return(res);
411 : : }
412 : :
413 : : /* The main GPG decryption routine for libfko.
414 : : */
415 : : int
416 : 75 : gpgme_decrypt(fko_ctx_t fko_ctx, unsigned char *indata,
417 : : size_t in_len, const char *pw, unsigned char **out, size_t *out_len)
418 : : {
419 : : char *tmp_buf;
420 : : int res;
421 : :
422 : 75 : gpgme_ctx_t gpg_ctx = NULL;
423 : 75 : gpgme_data_t cipher = NULL;
424 : 75 : gpgme_data_t plaintext = NULL;
425 : : gpgme_error_t err;
426 : : gpgme_decrypt_result_t decrypt_res;
427 : : gpgme_verify_result_t verify_res;
428 : :
429 : : /* Initialize gpgme
430 : : */
431 : 75 : res = init_gpgme(fko_ctx);
432 [ + - ]: 75 : if(res != FKO_SUCCESS)
433 : : return(res);
434 : :
435 : 75 : gpg_ctx = fko_ctx->gpg_ctx;
436 : :
437 : 75 : err = gpgme_data_new(&plaintext);
438 [ - + ]: 75 : if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
439 : : {
440 : 0 : gpgme_release(gpg_ctx);
441 : 0 : fko_ctx->gpg_ctx = NULL;
442 : :
443 : 0 : fko_ctx->gpg_err = err;
444 : :
445 : 0 : return(FKO_ERROR_GPGME_PLAINTEXT_DATA_OBJ);
446 : : }
447 : :
448 : : /* Initialize the cipher data (place into gpgme_data object)
449 : : */
450 : 75 : err = gpgme_data_new_from_mem(&cipher, (char*)indata, in_len, 0);
451 [ - + ]: 75 : if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
452 : : {
453 : 0 : gpgme_data_release(plaintext);
454 : 0 : gpgme_release(gpg_ctx);
455 : 0 : fko_ctx->gpg_ctx = NULL;
456 : :
457 : 0 : fko_ctx->gpg_err = err;
458 : :
459 : 0 : return(FKO_ERROR_GPGME_CIPHER_DATA_OBJ);
460 : : }
461 : :
462 : : /* Set the passphrase callback.
463 : : */
464 : 75 : gpgme_set_passphrase_cb(gpg_ctx, my_passphrase_cb, (void*)pw);
465 : :
466 : : /* Now decrypt and verify.
467 : : */
468 : 75 : err = gpgme_op_decrypt_verify(gpg_ctx, cipher, plaintext);
469 [ + + ]: 75 : if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
470 : : {
471 : 14 : gpgme_data_release(plaintext);
472 : 14 : gpgme_data_release(cipher);
473 : 14 : gpgme_release(gpg_ctx);
474 : 14 : fko_ctx->gpg_ctx = NULL;
475 : :
476 : 14 : fko_ctx->gpg_err = err;
477 : :
478 : 14 : return(FKO_ERROR_GPGME_DECRYPT_FAILED);
479 : : }
480 : :
481 : : /* Done with the cipher text.
482 : : */
483 : 61 : gpgme_data_release(cipher);
484 : :
485 : : /* We check the "usupported_algorithm" flag in the decrypt result.
486 : : */
487 : 61 : decrypt_res = gpgme_op_decrypt_result(gpg_ctx);
488 : :
489 [ - + ]: 61 : if(decrypt_res->unsupported_algorithm)
490 : : {
491 : 0 : gpgme_data_release(plaintext);
492 : 0 : gpgme_release(gpg_ctx);
493 : 0 : fko_ctx->gpg_ctx = NULL;
494 : :
495 : 0 : return(FKO_ERROR_GPGME_DECRYPT_UNSUPPORTED_ALGORITHM);
496 : : }
497 : :
498 : : /* Now verify the signatures if so configured.
499 : : */
500 [ + + ]: 61 : if(fko_ctx->verify_gpg_sigs)
501 : : {
502 : 60 : verify_res = gpgme_op_verify_result(gpg_ctx);
503 : :
504 : 60 : res = process_sigs(fko_ctx, verify_res);
505 : :
506 [ - + ]: 60 : if(res != FKO_SUCCESS)
507 : : {
508 : 0 : gpgme_data_release(plaintext);
509 : 0 : gpgme_release(gpg_ctx);
510 : 0 : fko_ctx->gpg_ctx = NULL;
511 : :
512 : 0 : return(res);
513 : : }
514 : : }
515 : :
516 : : /* Get the encrypted data and its length from the gpgme data object.
517 : : */
518 : 61 : tmp_buf = gpgme_data_release_and_get_mem(plaintext, out_len);
519 : :
520 : : /* Use calloc here with an extra byte because I am not sure if all systems
521 : : * will include the terminating NULL with the decrypted data (which is
522 : : * expected to be a string).
523 : : */
524 : 61 : *out = calloc(1, *out_len+1); /* This is freed upon fko_ctx destruction. */
525 : :
526 [ + - ]: 61 : if(*out == NULL)
527 : : res = FKO_ERROR_MEMORY_ALLOCATION;
528 : : else
529 : : {
530 : 61 : memcpy(*out, tmp_buf, *out_len);
531 : 61 : res = FKO_SUCCESS;
532 : : }
533 : :
534 : 61 : gpgme_free(tmp_buf);
535 : :
536 : 61 : return(res);
537 : : }
538 : :
539 : : #endif /* HAVE_LIBGPGME */
540 : :
541 : : /***EOF***/
|