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

Annotation of /trunk/src/OECrypto.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6 - (hide 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 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     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 twoaday 6 gpgme_set_textmode (gctx, 1);
322 twoaday 1 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 twoaday 6 gpgme_set_textmode (gctx, 1);
400 twoaday 1 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 twoaday 3 gpgme_error_t rc = 0;
576 twoaday 1 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