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