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

Annotation of /trunk/src/OECrypto.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations)
Mon Mar 27 12:47:50 2006 UTC (19 years, 1 month ago) by twoaday
File MIME type: text/plain
File size: 15417 byte(s)
cleanups.


1 twoaday 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     };
38    
39    
40 twoaday 10 /* Move the keyboard focus to the message window
41     to copy the text to the clipboard. */
42 twoaday 1 static void
43     set_focus (HWND main)
44     {
45     HWND doc, mime, msg;
46    
47     doc = FindWindowEx (main, NULL, "ME_DocHost", NULL );
48     mime = FindWindowEx (doc, NULL, "##MimeEdit_Server", NULL);
49     msg = FindWindowEx (mime, NULL, "Internet Explorer_Server", NULL);
50    
51     AttachThreadInput (GetCurrentThreadId (),
52     GetWindowThreadProcessId (main, NULL),
53     TRUE);
54    
55     SetFocus (doc);
56     SetFocus (mime);
57     SetFocus (msg);
58    
59     AttachThreadInput (GetCurrentThreadId (),
60     GetWindowThreadProcessId (main, NULL),
61     FALSE);
62     }
63    
64    
65     /* Copy the message to the clipboard and then return the clipboard
66     data (which is the message). */
67     static char*
68     window_get_message (HWND main_hwnd)
69     {
70     set_focus (main_hwnd);
71     SetForegroundWindow (main_hwnd);
72     SendMessage (main_hwnd, WM_COMMAND, MAKEWPARAM(ID_OE5_SELECTALL, 0), 0);
73     SendMessage (main_hwnd, WM_COMMAND, MAKEWPARAM(ID_OE5_COPY, 0), 0);
74    
75 twoaday 10 /* even so SendMessage() should wait, we wait for safety reasons. */
76 twoaday 1 Sleep (200);
77 twoaday 10 return get_clip_text (NULL);
78 twoaday 1 }
79    
80    
81     /* Paste the message given in @msg into the window @main_hwnd.
82     To make sure all existing text is overwritten, "select all"
83     is send to the window first. */
84     static void
85     window_set_message (HWND main_hwnd, const char *msg)
86     {
87     set_clip_text (NULL, msg, strlen (msg));
88     set_focus (main_hwnd);
89     SetForegroundWindow (main_hwnd);
90     SendMessage (main_hwnd, WM_COMMAND, MAKEWPARAM (ID_OE5_SELECTALL, 0), 0);
91     SendMessage (main_hwnd, WM_COMMAND, MAKEWPARAM (ID_OE5_PASTE, 0), 0);
92     }
93    
94    
95     /* Try to find the given recipient by key @key and
96     return it (NULL in case of error). */
97     static recip_list_t
98     find_recipient (recip_list_t rset, gpgme_key_t key)
99     {
100     recip_list_t n;
101     gpgme_user_id_t u;
102    
103     for (n = rset; n; n = n->next) {
104     for (u = key->uids; u; u = u->next) {
105     if (u->email && strstr (u->email, n->addr))
106     return n;
107     }
108     }
109     return NULL;
110     }
111    
112    
113     /* Add recipient with address @addr and key @key to @rset. */
114     void
115     add_recipient (recip_list_t *rset, const char *addr, gpgme_key_t key)
116     {
117     recip_list_t r, n;
118    
119     r = xcalloc (1, sizeof *r);
120     r->addr = xstrdup (addr);
121     r->key = key;
122     if (!*rset)
123     *rset = r;
124     else {
125     for (n=*rset; n->next; n=n->next)
126     ;
127     n->next = r;
128     }
129     }
130    
131    
132     /* Release recipient list @rset. */
133     static void
134     release_recipient (recip_list_t rset)
135     {
136     recip_list_t n;
137    
138     while (rset != NULL) {
139     n = rset->next;
140     if (rset->key)
141     gpgme_key_release (rset->key);
142     free_if_alloc (rset->addr);
143     free_if_alloc (rset);
144     rset = n;
145     }
146     }
147    
148    
149     /* This functions converts the OE recipient fields to GPG compatible fields.
150     Currently the function support the following 'From' styles:
151     John Hacker <[email protected]>; [email protected]
152     or Foo Bar <[email protected]>, [email protected].
153     only the part between '<' '>' are added.
154     */
155     static int
156     parse_recipients (plugin_ctx_t ctx, recip_list_t *rset, char *recpt)
157     {
158     char *token, *p;
159     int count = 0;
160     char *p1, *p2;
161     int n1, n2;
162    
163     assert (recpt && rset);
164    
165     token = strtok (recpt, ",;");
166     while (token != NULL ) {
167     if ((p1=strchr (token, '<')) && (p2=strchr (token, '>'))
168     && strchr (token, '@')) {
169     n1 = p1 - token + 1 ;
170     n2 = p2 - token + 1;
171    
172     p = xcalloc (1, strlen (token) + 1);
173     memcpy (p, token+n1, n2-n1-1);
174     add_recipient (rset, p, NULL);
175     count++;
176     free_if_alloc (p);
177     }
178     else if (strchr (token, '@') && !strchr (token, ' ')) {
179     p = xcalloc (1, strlen (token) + 1);
180     memcpy (p, token, strlen (token));
181     add_recipient (rset, p, NULL);
182     count++;
183     free_if_alloc (p);
184     }
185     token = strtok (NULL, ",;");
186     }
187     return count;
188     }
189    
190    
191 twoaday 10 /* Fill in the key part of the recipient list @addrs if possible. */
192 twoaday 1 static int
193     get_keys_from_addresses (recip_list_t addrs)
194     {
195     gpgme_ctx_t ctx;
196     gpgme_error_t err;
197     gpgme_key_t pk;
198     recip_list_t n, fnd;
199     char *p;
200     int nkeys=0;
201     DWORD len=0;
202    
203     for (n = addrs; n; n = n->next)
204     len += strlen (n->addr) + 3;
205     p = xcalloc (1, len + 1);
206     for (n = addrs; n; n = n->next) {
207     strcat (p, n->addr);
208     strcat (p, " ");
209     }
210    
211     err = gpgme_new (&ctx);
212     if (!err)
213     err = gpgme_op_keylist_start (ctx, p, 0);
214     while (!err) {
215     err = gpgme_op_keylist_next (ctx, &pk);
216     if (err)
217     break;
218 twoaday 10 /* do not add invalid keys. */
219 twoaday 1 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     /* Try to extract the needed key information and retrieve
250     the keys if possible. */
251     static gpgme_error_t
252     get_keys (plugin_ctx_t ctx, recip_list_t *r_list,
253     gpgme_key_t **r_keys, int *r_n)
254     {
255     gpgme_key_t *keys;
256     recip_list_t addrs = NULL, n;
257     int rcount = 0, nkeys = 0;
258     int i;
259    
260     if (ctx->to && strlen (ctx->to) >= 3)
261     rcount += parse_recipients (ctx, &addrs, ctx->to);
262     if (ctx->cc && strlen (ctx->cc) >= 3)
263     rcount += parse_recipients (ctx, &addrs, ctx->cc);
264     if (ctx->bcc && strlen (ctx->bcc) >= 3)
265     rcount += parse_recipients (ctx, &addrs, ctx->bcc);
266    
267     nkeys = get_keys_from_addresses (addrs);
268 twoaday 10 /* at least some keys were not found, so we offer to select them. */
269 twoaday 1 if (nkeys != rcount) {
270     ctx->rset = addrs;
271     rcount = DialogBoxParam (mod_hinst_dll, (LPCTSTR)IDD_ENCRYPT,
272     ctx->main_wnd, encrypt_dlg_proc, (LPARAM)ctx);
273     if (rcount == 0)
274     return gpg_error (GPG_ERR_NO_PUBKEY);
275     nkeys += rcount;
276     }
277    
278     keys = xcalloc (nkeys+1, sizeof *keys);
279     for (n = addrs, i=0; n; n = n->next) {
280     if (n->key != NULL)
281     keys[i++] = n->key;
282     }
283     *r_list = addrs;
284     *r_keys = keys;
285     *r_n = nkeys;
286     return 0;
287     }
288    
289    
290 twoaday 10 /* Encrypt the given message @r_msg with the recipients from the
291     To, Cc, Bcc fields. In case that a recipient was not found
292     use the recipient dialog so the user can select the missing keys. */
293 twoaday 1 static gpgme_error_t
294     encrypt_msg (plugin_ctx_t ctx, char **r_msg)
295     {
296     gpgme_error_t err;
297     gpgme_key_t *keys = NULL;
298     gpgme_ctx_t gctx = NULL;
299     gpgme_data_t in = NULL, out = NULL;
300     recip_list_t list = NULL;
301 twoaday 10 int nkeys=0;
302 twoaday 1 char *msg = *r_msg;
303    
304     assert (ctx);
305    
306 twoaday 10 err = get_keys (ctx, &list, &keys, &nkeys);
307     if (err)
308     return err;
309 twoaday 1
310     err = gpgme_new (&gctx);
311     if (!err)
312     err = gpgme_data_new_from_mem (&in, msg, strlen (msg), 1);
313     if (!err)
314     err = gpgme_data_new (&out);
315     if (!err) {
316     gpgme_set_armor (gctx, 1);
317 twoaday 6 gpgme_set_textmode (gctx, 1);
318 twoaday 10 err = gpgme_op_encrypt (gctx, keys,
319     GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
320 twoaday 1 }
321    
322     gpgme_release (gctx);
323     gpgme_data_release (in);
324     release_recipient (list);
325     free (keys);
326    
327 twoaday 10 if (err)
328 twoaday 1 gpgme_data_release (out);
329 twoaday 10 else
330     map_gpgme_data (out, r_msg);
331     return err;
332 twoaday 1 }
333    
334    
335 twoaday 10 /* Sign the message given in @r_msg with the GPG default key. */
336 twoaday 1 static gpgme_error_t
337     sign_msg (plugin_ctx_t ctx, char **r_msg)
338     {
339     gpgme_error_t err;
340     gpgme_ctx_t gctx;
341     gpgme_data_t in, out;
342     pass_cb_t cb_val;
343    
344     cb_val = new_pass_cb (ctx->main_wnd);
345    
346     err = gpgme_new (&gctx);
347     if (!err)
348     err = gpgme_data_new_from_mem (&in, *r_msg, strlen (*r_msg), 1);
349     if (!err)
350     err = gpgme_data_new (&out);
351     if (!err) {
352     gpgme_set_passphrase_cb (gctx, passphrase_cb, cb_val);
353     err = gpgme_op_sign (gctx, in, out, GPGME_SIG_MODE_CLEAR);
354     }
355    
356     gpgme_release (gctx);
357     gpgme_data_release (in);
358     free_pass_cb (cb_val);
359    
360 twoaday 10 if (err)
361 twoaday 1 gpgme_data_release (out);
362 twoaday 10 else
363     map_gpgme_data (out, r_msg);
364 twoaday 1
365 twoaday 10 return err;
366 twoaday 1 }
367    
368    
369 twoaday 10 /* Sign and encrypt the message @r_msg. */
370 twoaday 1 static gpgme_error_t
371     sign_encrypt_msg (plugin_ctx_t ctx, char **r_msg)
372     {
373     gpgme_ctx_t gctx;
374     gpgme_data_t in, out;
375     gpgme_error_t err;
376     gpgme_key_t *keys;
377     pass_cb_t cb_val;
378     recip_list_t list = NULL;
379     int ec, nkeys = 0;
380    
381     ec = get_keys (ctx, &list, &keys, &nkeys);
382     if (ec)
383     return ec;
384    
385     cb_val = new_pass_cb (ctx->main_wnd);
386    
387     err = gpgme_new (&gctx);
388     if (!err)
389     err = gpgme_data_new_from_mem (&in, *r_msg, strlen (*r_msg), 1);
390     if (!err)
391     err = gpgme_data_new (&out);
392     if (!err) {
393     gpgme_set_armor (gctx, 1);
394 twoaday 6 gpgme_set_textmode (gctx, 1);
395 twoaday 1 gpgme_set_passphrase_cb (gctx, passphrase_cb, cb_val);
396     err = gpgme_op_encrypt_sign (gctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST,
397     in, out);
398     }
399    
400     gpgme_release (gctx);
401     gpgme_data_release (in);
402     release_recipient (list);
403     free (keys);
404     free_pass_cb (cb_val);
405    
406 twoaday 10 if (err)
407 twoaday 1 gpgme_data_release (out);
408 twoaday 10 else
409     map_gpgme_data (out, r_msg);
410     return err;
411 twoaday 1 }
412    
413    
414     static gpgme_error_t
415     verify_msg (plugin_ctx_t ctx, char **r_msg)
416     {
417     gpgme_error_t err;
418     gpgme_ctx_t gctx;
419     gpgme_data_t out = NULL;
420     gpgme_data_t sig = NULL;
421     gpgme_verify_result_t res;
422    
423     err = gpgme_new (&gctx);
424     if (!err)
425     err = gpgme_data_new_from_mem (&sig, *r_msg, strlen (*r_msg), 1);
426     if (!err)
427     err = gpgme_data_new (&out);
428     if (!err)
429     err = gpgme_op_verify (gctx, sig, NULL, out);
430     if (!err) {
431     res = gpgme_op_verify_result (gctx);
432     if (res && res->signatures)
433     DialogBoxParam (mod_hinst_dll, (LPCTSTR)IDD_VERIFY, ctx->main_wnd,
434     verify_dlg_proc, (LPARAM)res->signatures);
435     }
436    
437     gpgme_release (gctx);
438     gpgme_data_release (sig);
439 twoaday 10
440     if (!err)
441     map_gpgme_data (out, r_msg);
442     else
443     gpgme_data_release (out);
444 twoaday 1 return err;
445     }
446    
447    
448     /* Detailed error message when the decryption failed. */
449     static void
450     store_decrypt_info (char *buf, size_t buflen,
451     gpgme_decrypt_result_t res)
452     {
453     gpgme_key_t key = NULL;
454     gpgme_ctx_t ctx;
455     int algo;
456    
457     if (!res->recipients)
458     return;
459    
460     if (!gpgme_new (&ctx)) {
461     gpgme_get_key (ctx, res->recipients->keyid, &key, 0);
462     gpgme_release (ctx);
463     }
464    
465     algo = res->recipients->pubkey_algo;
466     if (!key)
467     _snprintf (buf, buflen, _("encrypted with %s key, ID %s\n"
468     "decryption failed: secret keyn not available"),
469     algo == 1? "RSA" : algo==16? "ELG": "???",
470     res->recipients->keyid+8);
471     else {
472     char *uid = utf8_to_native (key->uids->uid);
473     _snprintf (buf, buflen, _("encrypted with %d-bit %s key, ID %s\n"
474     "\t\"%s\"\n"
475     "decryption failed: secret keyn not available"),
476     key->subkeys->length,
477     algo == 1? "RSA" : algo==16? "ELG": "???",
478     key->subkeys->keyid+8, uid);
479     free_if_alloc (uid);
480     }
481     if (key)
482     gpgme_key_release (key);
483     }
484    
485    
486 twoaday 10 /* Decrypt the message @r_msg. If the type @type is actually a signature,
487     the verify function is called instead of decryption. */
488 twoaday 1 static gpgme_error_t
489     decrypt_msg (plugin_ctx_t ctx, char **r_msg, int type)
490     {
491     gpgme_ctx_t gctx = NULL;
492     gpgme_data_t in = NULL, out = NULL;
493     gpgme_error_t err;
494     gpgme_verify_result_t res;
495     pass_cb_t cb_val;
496     char *msg = *r_msg;
497    
498     if ((type & PGP_SIG) || (type & PGP_CLEARSIG))
499     return verify_msg (ctx, r_msg);
500    
501     cb_val = new_pass_cb (ctx->main_wnd);
502    
503     err = gpgme_new (&gctx);
504     if (!err)
505     err = gpgme_data_new_from_mem (&in, msg, strlen (msg), 1);
506     if (!err)
507     err = gpgme_data_new (&out);
508     if (!err) {
509     gpgme_set_passphrase_cb (gctx, passphrase_cb, cb_val);
510     err = gpgme_op_decrypt_verify (gctx, in, out);
511     res = gpgme_op_verify_result (gctx);
512     if (res && res->signatures)
513     DialogBoxParam (mod_hinst_dll, (LPCTSTR)IDD_VERIFY, ctx->main_wnd,
514     verify_dlg_proc, (LPARAM)res->signatures);
515     }
516     if (err) {
517     gpgme_decrypt_result_t r = gpgme_op_decrypt_result (gctx);
518     store_decrypt_info (ctx->errbuf, sizeof (ctx->errbuf)-1, r);
519     }
520    
521     gpgme_release (gctx);
522     gpgme_data_release (in);
523     free_pass_cb (cb_val);
524    
525 twoaday 10 if (err)
526 twoaday 1 gpgme_data_release (out);
527 twoaday 10 else
528     map_gpgme_data (out, r_msg);
529 twoaday 1
530 twoaday 10 return err;
531 twoaday 1 }
532    
533    
534     /* Return what kind of OpenPGP message @msg is. */
535     static int
536     parse_pgp_id (const char *msg)
537     {
538     int id = 0;
539    
540     if (strstr (msg, "BEGIN PGP MESSAGE"))
541     id |= PGP_MESSAGE;
542     if (strstr (msg, "BEGIN PGP PUBLIC KEY") ||
543     strstr (msg, "BEGIN PGP SECRET KEY") ||
544     strstr (msg, "BEGIN PGP PRIVATE KEY"))
545     id |= PGP_KEY;
546     if (strstr (msg, "BEGIN PGP SIGNED MESSAGE"))
547     id |= PGP_CLEARSIG;
548     return id;
549     }
550    
551    
552     /* This function can be use for all kind of OE messages.
553     It automatically choose the right procedure to handle the data. */
554     gpgme_error_t
555     oe_handle_mail (plugin_ctx_t ctx)
556     {
557 twoaday 3 gpgme_error_t rc = 0;
558 twoaday 10 char *msg;
559 twoaday 1 int msg_type = 0;
560    
561     assert (ctx);
562    
563     msg = window_get_message (ctx->main_wnd);
564     if (!msg || strlen (msg) == 2) {
565     free_if_alloc (msg);
566     return 0;
567     }
568    
569     if (strstr (msg, "-----BEGIN PGP") &&
570     strstr (msg, "-----END PGP"))
571     msg_type = parse_pgp_id (msg);
572    
573     if (msg_type & PGP_KEY) {
574     MessageBox (ctx->main_wnd,
575     _("This mail contains one or more public or secret keys.\n\n"
576     "Please save the mail text in a file to use WinPT to import them."),
577     _("GPG Plug-in Info"), MB_ICONINFORMATION|MB_OK);
578     }
579     else if (msg_type) {
580     rc = decrypt_msg (ctx, &msg, msg_type);
581     SendMessage (ctx->msg_wnd, WM_CLEAR, 0, 0);
582     SendMessage (ctx->msg_wnd, WM_UNDO, 0, 0);
583     if (!rc && (msg_type & PGP_MESSAGE) && msg && strlen (msg) > 0) {
584     struct viewer_ctx_s viewer;
585     viewer.msg = msg;
586     DialogBoxParam (mod_hinst_dll, (LPCTSTR)IDD_VIEWER, ctx->main_wnd,
587     viewer_dlg_proc, (LPARAM)&viewer);
588     }
589     }
590     else {
591     if (!ctx->to && !ctx->cc && !ctx->bcc) {
592     free_if_alloc (msg);
593     return gpg_error (GPG_ERR_NO_DATA);
594     }
595     if (ctx->sign && ctx->encrypt)
596     rc = sign_encrypt_msg (ctx, &msg);
597     else if (ctx->sign)
598     rc = sign_msg (ctx, &msg);
599     else if (ctx->encrypt)
600     rc = encrypt_msg (ctx, &msg);
601     window_set_message (ctx->main_wnd, msg);
602     }
603    
604     free_if_alloc (msg);
605     return rc;
606     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26