/[gpgoe]/trunk/src/OECrypto.c
ViewVC logotype

Contents of /trunk/src/OECrypto.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Fri Mar 24 22:46:53 2006 UTC (19 years, 1 month ago) by twoaday
File MIME type: text/plain
File size: 15666 byte(s)
autoconf support.


1 /* OECrypto.c - OE crypto functions
2 * Copyright (C) 2001, 2002, 2003, 2006 Timo Schulz
3 *
4 * This file is part of GPGOE.
5 *
6 * GPGOE is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
10 *
11 * GPGOE is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with GPGOE; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <windows.h>
25 #include <assert.h>
26 #include "resource.h"
27 #include "gpgme.h"
28 #include "GPGOE.h"
29
30
31 /* Valid OpenPGP message types. */
32 enum {
33 PGP_MESSAGE = 1,
34 PGP_CLEARSIG = 2,
35 PGP_SIG = 4,
36 PGP_KEY = 8,
37 PGP_DASH_ESCAPED = 32
38 };
39
40
41 /* Move the keyboard focus to the message window to copy
42 the text to the clipboard. */
43 static void
44 set_focus (HWND main)
45 {
46 HWND doc, mime, msg;
47
48 doc = FindWindowEx (main, NULL, "ME_DocHost", NULL );
49 mime = FindWindowEx (doc, NULL, "##MimeEdit_Server", NULL);
50 msg = FindWindowEx (mime, NULL, "Internet Explorer_Server", NULL);
51
52 AttachThreadInput (GetCurrentThreadId (),
53 GetWindowThreadProcessId (main, NULL),
54 TRUE);
55
56 SetFocus (doc);
57 SetFocus (mime);
58 SetFocus (msg);
59
60 AttachThreadInput (GetCurrentThreadId (),
61 GetWindowThreadProcessId (main, NULL),
62 FALSE);
63 }
64
65
66 /* Copy the message to the clipboard and then return the clipboard
67 data (which is the message). */
68 static char*
69 window_get_message (HWND main_hwnd)
70 {
71 set_focus (main_hwnd);
72 SetForegroundWindow (main_hwnd);
73 SendMessage (main_hwnd, WM_COMMAND, MAKEWPARAM(ID_OE5_SELECTALL, 0), 0);
74 SendMessage (main_hwnd, WM_COMMAND, MAKEWPARAM(ID_OE5_COPY, 0), 0);
75
76 Sleep (200);
77
78 return get_clip_text (NULL);;
79 }
80
81
82 /* Paste the message given in @msg into the window @main_hwnd.
83 To make sure all existing text is overwritten, "select all"
84 is send to the window first. */
85 static void
86 window_set_message (HWND main_hwnd, const char *msg)
87 {
88 set_clip_text (NULL, msg, strlen (msg));
89 set_focus (main_hwnd);
90 SetForegroundWindow (main_hwnd);
91 SendMessage (main_hwnd, WM_COMMAND, MAKEWPARAM (ID_OE5_SELECTALL, 0), 0);
92 SendMessage (main_hwnd, WM_COMMAND, MAKEWPARAM (ID_OE5_PASTE, 0), 0);
93 }
94
95
96 /* Try to find the given recipient by key @key and
97 return it (NULL in case of error). */
98 static recip_list_t
99 find_recipient (recip_list_t rset, gpgme_key_t key)
100 {
101 recip_list_t n;
102 gpgme_user_id_t u;
103
104 for (n = rset; n; n = n->next) {
105 for (u = key->uids; u; u = u->next) {
106 if (u->email && strstr (u->email, n->addr))
107 return n;
108 }
109 }
110 return NULL;
111 }
112
113
114 /* Add recipient with address @addr and key @key to @rset. */
115 void
116 add_recipient (recip_list_t *rset, const char *addr, gpgme_key_t key)
117 {
118 recip_list_t r, n;
119
120 r = xcalloc (1, sizeof *r);
121 r->addr = xstrdup (addr);
122 r->key = key;
123 if (!*rset)
124 *rset = r;
125 else {
126 for (n=*rset; n->next; n=n->next)
127 ;
128 n->next = r;
129 }
130 }
131
132
133 /* Release recipient list @rset. */
134 static void
135 release_recipient (recip_list_t rset)
136 {
137 recip_list_t n;
138
139 while (rset != NULL) {
140 n = rset->next;
141 if (rset->key)
142 gpgme_key_release (rset->key);
143 free_if_alloc (rset->addr);
144 free_if_alloc (rset);
145 rset = n;
146 }
147 }
148
149
150 /* This functions converts the OE recipient fields to GPG compatible fields.
151 Currently the function support the following 'From' styles:
152 John Hacker <[email protected]>; [email protected]
153 or Foo Bar <[email protected]>, [email protected].
154 only the part between '<' '>' are added.
155 */
156 static int
157 parse_recipients (plugin_ctx_t ctx, recip_list_t *rset, char *recpt)
158 {
159 char *token, *p;
160 int count = 0;
161 char *p1, *p2;
162 int n1, n2;
163
164 assert (recpt && rset);
165
166 token = strtok (recpt, ",;");
167 while (token != NULL ) {
168 if ((p1=strchr (token, '<')) && (p2=strchr (token, '>'))
169 && strchr (token, '@')) {
170 n1 = p1 - token + 1 ;
171 n2 = p2 - token + 1;
172
173 p = xcalloc (1, strlen (token) + 1);
174 memcpy (p, token+n1, n2-n1-1);
175 add_recipient (rset, p, NULL);
176 count++;
177 free_if_alloc (p);
178 }
179 else if (strchr (token, '@') && !strchr (token, ' ')) {
180 p = xcalloc (1, strlen (token) + 1);
181 memcpy (p, token, strlen (token));
182 add_recipient (rset, p, NULL);
183 count++;
184 free_if_alloc (p);
185 }
186 token = strtok (NULL, ",;");
187 }
188 return count;
189 }
190
191
192 /* Fill in the key part of the recipient list if possible. */
193 static int
194 get_keys_from_addresses (recip_list_t addrs)
195 {
196 gpgme_ctx_t ctx;
197 gpgme_error_t err;
198 gpgme_key_t pk;
199 recip_list_t n, fnd;
200 char *p;
201 int nkeys=0;
202 DWORD len=0;
203
204 for (n = addrs; n; n = n->next)
205 len += strlen (n->addr) + 3;
206 p = xcalloc (1, len + 1);
207 for (n = addrs; n; n = n->next) {
208 strcat (p, n->addr);
209 strcat (p, " ");
210 }
211
212 err = gpgme_new (&ctx);
213 if (!err)
214 err = gpgme_op_keylist_start (ctx, p, 0);
215 while (!err) {
216 err = gpgme_op_keylist_next (ctx, &pk);
217 if (err)
218 break;
219 if (pk->disabled || pk->expired || pk->revoked)
220 continue;
221 fnd = find_recipient (addrs, pk);
222 if (fnd != NULL && pk->can_encrypt) {
223 fnd->key = pk;
224 nkeys++;
225 }
226 }
227
228 gpgme_release (ctx);
229 free_if_alloc (p);
230 return nkeys;
231 }
232
233
234 /* Map gpgme data object to a string. */
235 void
236 map_gpgme_data (gpgme_data_t out, char **r_msg)
237 {
238 size_t len = 0;
239 char *p;
240
241 p = gpgme_data_release_and_get_mem (out, &len);
242 free_if_alloc (*r_msg);
243 *r_msg = xcalloc (1, len+1);
244 memcpy (*r_msg, p, len);
245 gpgme_free (p);
246 }
247
248
249
250
251
252 /* Try to extract the needed key information and retrieve
253 the keys if possible. */
254 static gpgme_error_t
255 get_keys (plugin_ctx_t ctx, recip_list_t *r_list,
256 gpgme_key_t **r_keys, int *r_n)
257 {
258 gpgme_key_t *keys;
259 recip_list_t addrs = NULL, n;
260 int rcount = 0, nkeys = 0;
261 int i;
262
263 if (ctx->to && strlen (ctx->to) >= 3)
264 rcount += parse_recipients (ctx, &addrs, ctx->to);
265 if (ctx->cc && strlen (ctx->cc) >= 3)
266 rcount += parse_recipients (ctx, &addrs, ctx->cc);
267 if (ctx->bcc && strlen (ctx->bcc) >= 3)
268 rcount += parse_recipients (ctx, &addrs, ctx->bcc);
269
270 nkeys = get_keys_from_addresses (addrs);
271 if (nkeys != rcount) {
272 ctx->rset = addrs;
273 rcount = DialogBoxParam (mod_hinst_dll, (LPCTSTR)IDD_ENCRYPT,
274 ctx->main_wnd, encrypt_dlg_proc, (LPARAM)ctx);
275 if (rcount == 0)
276 return gpg_error (GPG_ERR_NO_PUBKEY);
277 nkeys += rcount;
278 }
279
280 keys = xcalloc (nkeys+1, sizeof *keys);
281 for (n = addrs, i=0; n; n = n->next) {
282 if (n->key != NULL)
283 keys[i++] = n->key;
284 }
285 *r_list = addrs;
286 *r_keys = keys;
287 *r_n = nkeys;
288 return 0;
289 }
290
291
292 /* For this function we think that the clipboard contains the data which
293 should be encrypted.
294 After all recipient headers are converted to valid GPG recipients the
295 message is encrypted. In the case that the OE recipients are not
296 available in the GPG keyring, an keylist is shown. */
297 static gpgme_error_t
298 encrypt_msg (plugin_ctx_t ctx, char **r_msg)
299 {
300 gpgme_error_t err;
301 gpgme_key_t *keys = NULL;
302 gpgme_ctx_t gctx = NULL;
303 gpgme_data_t in = NULL, out = NULL;
304 recip_list_t list = NULL;
305 int ec = 0, nkeys=0;
306 char *msg = *r_msg;
307
308 assert (ctx);
309
310 ec = get_keys (ctx, &list, &keys, &nkeys);
311 if (ec)
312 return ec;
313
314 err = gpgme_new (&gctx);
315 if (!err)
316 err = gpgme_data_new_from_mem (&in, msg, strlen (msg), 1);
317 if (!err)
318 err = gpgme_data_new (&out);
319 if (!err) {
320 gpgme_set_armor (gctx, 1);
321 err = gpgme_op_encrypt (gctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
322 }
323
324 gpgme_release (gctx);
325 gpgme_data_release (in);
326 release_recipient (list);
327 free (keys);
328
329 if (err) {
330 gpgme_data_release (out);
331 return err;
332 }
333
334 map_gpgme_data (out, r_msg);
335 return 0;
336 }
337
338
339 static gpgme_error_t
340 sign_msg (plugin_ctx_t ctx, char **r_msg)
341 {
342 gpgme_error_t err;
343 gpgme_ctx_t gctx;
344 gpgme_data_t in, out;
345 pass_cb_t cb_val;
346
347 cb_val = new_pass_cb (ctx->main_wnd);
348
349 err = gpgme_new (&gctx);
350 if (!err)
351 err = gpgme_data_new_from_mem (&in, *r_msg, strlen (*r_msg), 1);
352 if (!err)
353 err = gpgme_data_new (&out);
354 if (!err) {
355 gpgme_set_passphrase_cb (gctx, passphrase_cb, cb_val);
356 err = gpgme_op_sign (gctx, in, out, GPGME_SIG_MODE_CLEAR);
357 }
358
359 gpgme_release (gctx);
360 gpgme_data_release (in);
361 free_pass_cb (cb_val);
362
363 if (err) {
364 gpgme_data_release (out);
365 return err;
366 }
367
368 map_gpgme_data (out, r_msg);
369
370 return 0;
371 }
372
373
374 static gpgme_error_t
375 sign_encrypt_msg (plugin_ctx_t ctx, char **r_msg)
376 {
377 gpgme_ctx_t gctx;
378 gpgme_data_t in, out;
379 gpgme_error_t err;
380 gpgme_key_t *keys;
381 pass_cb_t cb_val;
382 recip_list_t list = NULL;
383 int ec, nkeys = 0;
384
385 ec = get_keys (ctx, &list, &keys, &nkeys);
386 if (ec)
387 return ec;
388
389 cb_val = new_pass_cb (ctx->main_wnd);
390
391 err = gpgme_new (&gctx);
392 if (!err)
393 err = gpgme_data_new_from_mem (&in, *r_msg, strlen (*r_msg), 1);
394 if (!err)
395 err = gpgme_data_new (&out);
396 if (!err) {
397 gpgme_set_armor (gctx, 1);
398 gpgme_set_passphrase_cb (gctx, passphrase_cb, cb_val);
399 err = gpgme_op_encrypt_sign (gctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST,
400 in, out);
401 }
402
403 gpgme_release (gctx);
404 gpgme_data_release (in);
405 release_recipient (list);
406 free (keys);
407 free_pass_cb (cb_val);
408
409 if (err) {
410 gpgme_data_release (out);
411 return err;
412 }
413
414 map_gpgme_data (out, r_msg);
415 return 0;
416 }
417
418
419 static gpgme_error_t
420 verify_msg (plugin_ctx_t ctx, char **r_msg)
421 {
422 gpgme_error_t err;
423 gpgme_ctx_t gctx;
424 gpgme_data_t out = NULL;
425 gpgme_data_t sig = NULL;
426 gpgme_verify_result_t res;
427
428 err = gpgme_new (&gctx);
429 if (!err)
430 err = gpgme_data_new_from_mem (&sig, *r_msg, strlen (*r_msg), 1);
431 if (!err)
432 err = gpgme_data_new (&out);
433 if (!err)
434 err = gpgme_op_verify (gctx, sig, NULL, out);
435 if (!err) {
436 res = gpgme_op_verify_result (gctx);
437 if (res && res->signatures)
438 DialogBoxParam (mod_hinst_dll, (LPCTSTR)IDD_VERIFY, ctx->main_wnd,
439 verify_dlg_proc, (LPARAM)res->signatures);
440 }
441
442 gpgme_release (gctx);
443 gpgme_data_release (sig);
444 map_gpgme_data (out, r_msg);
445
446 return err;
447 }
448
449
450 /* Detailed error message when the decryption failed. */
451 static void
452 store_decrypt_info (char *buf, size_t buflen,
453 gpgme_decrypt_result_t res)
454 {
455 gpgme_key_t key = NULL;
456 gpgme_ctx_t ctx;
457 int algo;
458
459 if (!res->recipients)
460 return;
461
462 if (!gpgme_new (&ctx)) {
463 gpgme_get_key (ctx, res->recipients->keyid, &key, 0);
464 gpgme_release (ctx);
465 }
466
467 algo = res->recipients->pubkey_algo;
468 if (!key)
469 _snprintf (buf, buflen, _("encrypted with %s key, ID %s\n"
470 "decryption failed: secret keyn not available"),
471 algo == 1? "RSA" : algo==16? "ELG": "???",
472 res->recipients->keyid+8);
473 else {
474 char *uid = utf8_to_native (key->uids->uid);
475 _snprintf (buf, buflen, _("encrypted with %d-bit %s key, ID %s\n"
476 "\t\"%s\"\n"
477 "decryption failed: secret keyn not available"),
478 key->subkeys->length,
479 algo == 1? "RSA" : algo==16? "ELG": "???",
480 key->subkeys->keyid+8, uid);
481 free_if_alloc (uid);
482 }
483 if (key)
484 gpgme_key_release (key);
485 }
486
487
488 /* For this function we think that the clipboard contains the data which
489 should be encrypted.
490 Actually the functions can differ between the various PGP messages.
491 In the case encrypted data is detected, it tries to decrypt it
492 with a passphrase callback which is equal to the signing procedure.
493 The other possibility is that the data is a clearsigned signature.
494 Then the signature is verified and the status is shown. */
495 static gpgme_error_t
496 decrypt_msg (plugin_ctx_t ctx, char **r_msg, int type)
497 {
498 gpgme_ctx_t gctx = NULL;
499 gpgme_data_t in = NULL, out = NULL;
500 gpgme_error_t err;
501 gpgme_verify_result_t res;
502
503 pass_cb_t cb_val;
504 char *msg = *r_msg;
505 char *p;
506 size_t len;
507
508 if ((type & PGP_SIG) || (type & PGP_CLEARSIG))
509 return verify_msg (ctx, r_msg);
510
511 cb_val = new_pass_cb (ctx->main_wnd);
512
513 err = gpgme_new (&gctx);
514 if (!err)
515 err = gpgme_data_new_from_mem (&in, msg, strlen (msg), 1);
516 if (!err)
517 err = gpgme_data_new (&out);
518 if (!err) {
519 gpgme_set_passphrase_cb (gctx, passphrase_cb, cb_val);
520 err = gpgme_op_decrypt_verify (gctx, in, out);
521 res = gpgme_op_verify_result (gctx);
522 if (res && res->signatures)
523 DialogBoxParam (mod_hinst_dll, (LPCTSTR)IDD_VERIFY, ctx->main_wnd,
524 verify_dlg_proc, (LPARAM)res->signatures);
525 }
526 if (err) {
527 gpgme_decrypt_result_t r = gpgme_op_decrypt_result (gctx);
528 store_decrypt_info (ctx->errbuf, sizeof (ctx->errbuf)-1, r);
529 }
530
531 gpgme_release (gctx);
532 gpgme_data_release (in);
533 free_pass_cb (cb_val);
534
535 if (err) {
536 gpgme_data_release (out);
537 return err;
538 }
539
540 p = gpgme_data_release_and_get_mem (out, &len);
541 free_if_alloc (msg);
542 *r_msg = xcalloc (1, len+1);
543 memcpy (*r_msg, p, len);
544 gpgme_free (p);
545
546 return 0;
547 }
548
549
550 /* Return what kind of OpenPGP message @msg is. */
551 static int
552 parse_pgp_id (const char *msg)
553 {
554 int id = 0;
555
556 if (strstr (msg, "BEGIN PGP MESSAGE"))
557 id |= PGP_MESSAGE;
558 if (strstr (msg, "BEGIN PGP PUBLIC KEY") ||
559 strstr (msg, "BEGIN PGP SECRET KEY") ||
560 strstr (msg, "BEGIN PGP PRIVATE KEY"))
561 id |= PGP_KEY;
562 if (strstr (msg, "BEGIN PGP SIGNED MESSAGE"))
563 id |= PGP_CLEARSIG;
564 return id;
565 }
566
567
568 /* This function can be use for all kind of OE messages.
569 It automatically choose the right procedure to handle the data. */
570 gpgme_error_t
571 oe_handle_mail (plugin_ctx_t ctx)
572 {
573 gpgme_error_t rc = 0;
574 char *msg = NULL;
575 int msg_type = 0;
576
577 assert (ctx);
578
579 msg = window_get_message (ctx->main_wnd);
580 if (!msg || strlen (msg) == 2) {
581 free_if_alloc (msg);
582 return 0;
583 }
584
585 if (strstr (msg, "-----BEGIN PGP") &&
586 strstr (msg, "-----END PGP"))
587 msg_type = parse_pgp_id (msg);
588
589 if (msg_type & PGP_KEY) {
590 MessageBox (ctx->main_wnd,
591 _("This mail contains one or more public or secret keys.\n\n"
592 "Please save the mail text in a file to use WinPT to import them."),
593 _("GPG Plug-in Info"), MB_ICONINFORMATION|MB_OK);
594 }
595 else if (msg_type) {
596 rc = decrypt_msg (ctx, &msg, msg_type);
597 SendMessage (ctx->msg_wnd, WM_CLEAR, 0, 0);
598 SendMessage (ctx->msg_wnd, WM_UNDO, 0, 0);
599 if (!rc && (msg_type & PGP_MESSAGE) && msg && strlen (msg) > 0) {
600 struct viewer_ctx_s viewer;
601 viewer.msg = msg;
602 DialogBoxParam (mod_hinst_dll, (LPCTSTR)IDD_VIEWER, ctx->main_wnd,
603 viewer_dlg_proc, (LPARAM)&viewer);
604 }
605 }
606 else {
607 if (!ctx->to && !ctx->cc && !ctx->bcc) {
608 free_if_alloc (msg);
609 return gpg_error (GPG_ERR_NO_DATA);
610 }
611 if (ctx->sign && ctx->encrypt)
612 rc = sign_encrypt_msg (ctx, &msg);
613 else if (ctx->sign)
614 rc = sign_msg (ctx, &msg);
615 else if (ctx->encrypt)
616 rc = encrypt_msg (ctx, &msg);
617 window_set_message (ctx->main_wnd, msg);
618 }
619
620 free_if_alloc (msg);
621 return rc;
622 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26