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

Contents of /trunk/src/OECrypto.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6 - (show annotations)
Sun Mar 26 10:39:09 2006 UTC (19 years, 1 month ago) by twoaday
File MIME type: text/plain
File size: 15728 byte(s)


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 gpgme_set_textmode (gctx, 1);
322 err = gpgme_op_encrypt (gctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
323 }
324
325 gpgme_release (gctx);
326 gpgme_data_release (in);
327 release_recipient (list);
328 free (keys);
329
330 if (err) {
331 gpgme_data_release (out);
332 return err;
333 }
334
335 map_gpgme_data (out, r_msg);
336 return 0;
337 }
338
339
340 static gpgme_error_t
341 sign_msg (plugin_ctx_t ctx, char **r_msg)
342 {
343 gpgme_error_t err;
344 gpgme_ctx_t gctx;
345 gpgme_data_t in, out;
346 pass_cb_t cb_val;
347
348 cb_val = new_pass_cb (ctx->main_wnd);
349
350 err = gpgme_new (&gctx);
351 if (!err)
352 err = gpgme_data_new_from_mem (&in, *r_msg, strlen (*r_msg), 1);
353 if (!err)
354 err = gpgme_data_new (&out);
355 if (!err) {
356 gpgme_set_passphrase_cb (gctx, passphrase_cb, cb_val);
357 err = gpgme_op_sign (gctx, in, out, GPGME_SIG_MODE_CLEAR);
358 }
359
360 gpgme_release (gctx);
361 gpgme_data_release (in);
362 free_pass_cb (cb_val);
363
364 if (err) {
365 gpgme_data_release (out);
366 return err;
367 }
368
369 map_gpgme_data (out, r_msg);
370
371 return 0;
372 }
373
374
375 static gpgme_error_t
376 sign_encrypt_msg (plugin_ctx_t ctx, char **r_msg)
377 {
378 gpgme_ctx_t gctx;
379 gpgme_data_t in, out;
380 gpgme_error_t err;
381 gpgme_key_t *keys;
382 pass_cb_t cb_val;
383 recip_list_t list = NULL;
384 int ec, nkeys = 0;
385
386 ec = get_keys (ctx, &list, &keys, &nkeys);
387 if (ec)
388 return ec;
389
390 cb_val = new_pass_cb (ctx->main_wnd);
391
392 err = gpgme_new (&gctx);
393 if (!err)
394 err = gpgme_data_new_from_mem (&in, *r_msg, strlen (*r_msg), 1);
395 if (!err)
396 err = gpgme_data_new (&out);
397 if (!err) {
398 gpgme_set_armor (gctx, 1);
399 gpgme_set_textmode (gctx, 1);
400 gpgme_set_passphrase_cb (gctx, passphrase_cb, cb_val);
401 err = gpgme_op_encrypt_sign (gctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST,
402 in, out);
403 }
404
405 gpgme_release (gctx);
406 gpgme_data_release (in);
407 release_recipient (list);
408 free (keys);
409 free_pass_cb (cb_val);
410
411 if (err) {
412 gpgme_data_release (out);
413 return err;
414 }
415
416 map_gpgme_data (out, r_msg);
417 return 0;
418 }
419
420
421 static gpgme_error_t
422 verify_msg (plugin_ctx_t ctx, char **r_msg)
423 {
424 gpgme_error_t err;
425 gpgme_ctx_t gctx;
426 gpgme_data_t out = NULL;
427 gpgme_data_t sig = NULL;
428 gpgme_verify_result_t res;
429
430 err = gpgme_new (&gctx);
431 if (!err)
432 err = gpgme_data_new_from_mem (&sig, *r_msg, strlen (*r_msg), 1);
433 if (!err)
434 err = gpgme_data_new (&out);
435 if (!err)
436 err = gpgme_op_verify (gctx, sig, NULL, out);
437 if (!err) {
438 res = gpgme_op_verify_result (gctx);
439 if (res && res->signatures)
440 DialogBoxParam (mod_hinst_dll, (LPCTSTR)IDD_VERIFY, ctx->main_wnd,
441 verify_dlg_proc, (LPARAM)res->signatures);
442 }
443
444 gpgme_release (gctx);
445 gpgme_data_release (sig);
446 map_gpgme_data (out, r_msg);
447
448 return err;
449 }
450
451
452 /* Detailed error message when the decryption failed. */
453 static void
454 store_decrypt_info (char *buf, size_t buflen,
455 gpgme_decrypt_result_t res)
456 {
457 gpgme_key_t key = NULL;
458 gpgme_ctx_t ctx;
459 int algo;
460
461 if (!res->recipients)
462 return;
463
464 if (!gpgme_new (&ctx)) {
465 gpgme_get_key (ctx, res->recipients->keyid, &key, 0);
466 gpgme_release (ctx);
467 }
468
469 algo = res->recipients->pubkey_algo;
470 if (!key)
471 _snprintf (buf, buflen, _("encrypted with %s key, ID %s\n"
472 "decryption failed: secret keyn not available"),
473 algo == 1? "RSA" : algo==16? "ELG": "???",
474 res->recipients->keyid+8);
475 else {
476 char *uid = utf8_to_native (key->uids->uid);
477 _snprintf (buf, buflen, _("encrypted with %d-bit %s key, ID %s\n"
478 "\t\"%s\"\n"
479 "decryption failed: secret keyn not available"),
480 key->subkeys->length,
481 algo == 1? "RSA" : algo==16? "ELG": "???",
482 key->subkeys->keyid+8, uid);
483 free_if_alloc (uid);
484 }
485 if (key)
486 gpgme_key_release (key);
487 }
488
489
490 /* For this function we think that the clipboard contains the data which
491 should be encrypted.
492 Actually the functions can differ between the various PGP messages.
493 In the case encrypted data is detected, it tries to decrypt it
494 with a passphrase callback which is equal to the signing procedure.
495 The other possibility is that the data is a clearsigned signature.
496 Then the signature is verified and the status is shown. */
497 static gpgme_error_t
498 decrypt_msg (plugin_ctx_t ctx, char **r_msg, int type)
499 {
500 gpgme_ctx_t gctx = NULL;
501 gpgme_data_t in = NULL, out = NULL;
502 gpgme_error_t err;
503 gpgme_verify_result_t res;
504
505 pass_cb_t cb_val;
506 char *msg = *r_msg;
507 char *p;
508 size_t len;
509
510 if ((type & PGP_SIG) || (type & PGP_CLEARSIG))
511 return verify_msg (ctx, r_msg);
512
513 cb_val = new_pass_cb (ctx->main_wnd);
514
515 err = gpgme_new (&gctx);
516 if (!err)
517 err = gpgme_data_new_from_mem (&in, msg, strlen (msg), 1);
518 if (!err)
519 err = gpgme_data_new (&out);
520 if (!err) {
521 gpgme_set_passphrase_cb (gctx, passphrase_cb, cb_val);
522 err = gpgme_op_decrypt_verify (gctx, in, out);
523 res = gpgme_op_verify_result (gctx);
524 if (res && res->signatures)
525 DialogBoxParam (mod_hinst_dll, (LPCTSTR)IDD_VERIFY, ctx->main_wnd,
526 verify_dlg_proc, (LPARAM)res->signatures);
527 }
528 if (err) {
529 gpgme_decrypt_result_t r = gpgme_op_decrypt_result (gctx);
530 store_decrypt_info (ctx->errbuf, sizeof (ctx->errbuf)-1, r);
531 }
532
533 gpgme_release (gctx);
534 gpgme_data_release (in);
535 free_pass_cb (cb_val);
536
537 if (err) {
538 gpgme_data_release (out);
539 return err;
540 }
541
542 p = gpgme_data_release_and_get_mem (out, &len);
543 free_if_alloc (msg);
544 *r_msg = xcalloc (1, len+1);
545 memcpy (*r_msg, p, len);
546 gpgme_free (p);
547
548 return 0;
549 }
550
551
552 /* Return what kind of OpenPGP message @msg is. */
553 static int
554 parse_pgp_id (const char *msg)
555 {
556 int id = 0;
557
558 if (strstr (msg, "BEGIN PGP MESSAGE"))
559 id |= PGP_MESSAGE;
560 if (strstr (msg, "BEGIN PGP PUBLIC KEY") ||
561 strstr (msg, "BEGIN PGP SECRET KEY") ||
562 strstr (msg, "BEGIN PGP PRIVATE KEY"))
563 id |= PGP_KEY;
564 if (strstr (msg, "BEGIN PGP SIGNED MESSAGE"))
565 id |= PGP_CLEARSIG;
566 return id;
567 }
568
569
570 /* This function can be use for all kind of OE messages.
571 It automatically choose the right procedure to handle the data. */
572 gpgme_error_t
573 oe_handle_mail (plugin_ctx_t ctx)
574 {
575 gpgme_error_t rc = 0;
576 char *msg = NULL;
577 int msg_type = 0;
578
579 assert (ctx);
580
581 msg = window_get_message (ctx->main_wnd);
582 if (!msg || strlen (msg) == 2) {
583 free_if_alloc (msg);
584 return 0;
585 }
586
587 if (strstr (msg, "-----BEGIN PGP") &&
588 strstr (msg, "-----END PGP"))
589 msg_type = parse_pgp_id (msg);
590
591 if (msg_type & PGP_KEY) {
592 MessageBox (ctx->main_wnd,
593 _("This mail contains one or more public or secret keys.\n\n"
594 "Please save the mail text in a file to use WinPT to import them."),
595 _("GPG Plug-in Info"), MB_ICONINFORMATION|MB_OK);
596 }
597 else if (msg_type) {
598 rc = decrypt_msg (ctx, &msg, msg_type);
599 SendMessage (ctx->msg_wnd, WM_CLEAR, 0, 0);
600 SendMessage (ctx->msg_wnd, WM_UNDO, 0, 0);
601 if (!rc && (msg_type & PGP_MESSAGE) && msg && strlen (msg) > 0) {
602 struct viewer_ctx_s viewer;
603 viewer.msg = msg;
604 DialogBoxParam (mod_hinst_dll, (LPCTSTR)IDD_VIEWER, ctx->main_wnd,
605 viewer_dlg_proc, (LPARAM)&viewer);
606 }
607 }
608 else {
609 if (!ctx->to && !ctx->cc && !ctx->bcc) {
610 free_if_alloc (msg);
611 return gpg_error (GPG_ERR_NO_DATA);
612 }
613 if (ctx->sign && ctx->encrypt)
614 rc = sign_encrypt_msg (ctx, &msg);
615 else if (ctx->sign)
616 rc = sign_msg (ctx, &msg);
617 else if (ctx->encrypt)
618 rc = encrypt_msg (ctx, &msg);
619 window_set_message (ctx->main_wnd, msg);
620 }
621
622 free_if_alloc (msg);
623 return rc;
624 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26