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

Annotation of /trunk/src/OECrypto.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Fri Mar 24 13:36:54 2006 UTC (19 years, 1 month ago) by twoaday
File MIME type: text/plain
File size: 15662 byte(s)
Initial checkin of the GPGOE code.


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     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;
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