/[winpt]/trunk/Src/wptPassphraseCB.cpp
ViewVC logotype

Annotation of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (hide annotations)
Mon Oct 24 08:03:48 2005 UTC (19 years, 4 months ago) by twoaday
File size: 12913 byte(s)
2005-10-23  Timo Schulz  <twoaday@g10code.com>
 
        * wptFileManager.cpp (fm_get_file_type): Detect detached sigs.
        * wptKeyList.cpp (keylist_cmp_cb): Take care of expired/revoked keys.
        (get_ext_validity): New.
        * wptFileVerifyDlg.cpp (file_verify_dlg_proc): Several cleanups.
        * wptClipEditDlg.cpp (load_clipboard): Factored out some code into
        this function.
        (load_clipboard_from_file): Likewise.
        (save_clipboard_to_file): New.
        * wptKeyManagerDlg.cpp (keyprops_dlg_proc): Fix stack overflow.

For complete details, see the ChangeLog files.

1 twoaday 2 /* wptPassphraseCB.cpp - GPGME Passphrase Callback
2 twoaday 23 * Copyright (C) 2001, 2002, 2003, 2005 Timo Schulz
3 twoaday 24 * Copyright (C) 2005 g10 Code GmbH
4 twoaday 2 *
5     * This file is part of WinPT.
6     *
7     * WinPT is free software; you can redistribute it and/or
8     * modify it under the terms of the GNU General Public License
9     * as published by the Free Software Foundation; either version 2
10     * of the License, or (at your option) any later version.
11     *
12     * WinPT is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15     * General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with WinPT; if not, write to the Free Software Foundation,
19     * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20     */
21    
22     #include <windows.h>
23     #include <ctype.h>
24    
25     #include "../resource.h"
26     #include "wptNLS.h"
27     #include "wptW32API.h"
28     #include "wptVersion.h"
29     #include "wptGPG.h"
30     #include "wptCommonCtl.h"
31     #include "wptContext.h"
32     #include "wptDlgs.h"
33     #include "wptUTF8.h"
34     #include "wptErrors.h"
35     #include "wptTypes.h"
36 twoaday 23 #include "wptKeyList.h"
37 twoaday 2 #include "wptAgent.h"
38     #include "wptRegistry.h"
39    
40 twoaday 25 const char* get_symkey_algo (int algo);
41 twoaday 2
42     #define item_ctrl_id( cmd ) \
43     ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_PWD : IDC_DECRYPT_SIGN_PWD)
44    
45 twoaday 22 #define item_ctrl_id2(cmd) \
46     ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_HIDE : IDC_DECRYPT_SIGN_HIDE)
47 twoaday 2
48 twoaday 22
49 twoaday 26 /* Overwrite passphrase and free memory. */
50     static void
51     burn_passphrase (char **pwd)
52     {
53 twoaday 32 char *pass = *pwd;
54     wipememory (pass, strlen (pass));
55 twoaday 26 delete []pass;
56     *pwd = NULL;
57     }
58    
59    
60 twoaday 23 /* Dialog procedure for the passphrase callback. */
61     static BOOL CALLBACK
62 twoaday 4 passphrase_callback_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
63 twoaday 2 {
64     static passphrase_cb_s * c;
65 twoaday 24 gpgme_decrypt_result_t res;
66     gpgme_sign_result_t res_sig;
67 twoaday 2 gpgme_key_t key;
68 twoaday 25 void *ctx = NULL, *item;
69 twoaday 23 const char *id;
70     char *info;
71     int n;
72 twoaday 2
73 twoaday 24 switch (msg) {
74 twoaday 2 case WM_INITDIALOG:
75     c = (passphrase_cb_s *)lparam;
76 twoaday 4 if (!c)
77     BUG (0);
78     SetWindowText (dlg, c->title);
79     if (c->gpg_cmd == GPG_CMD_DECRYPT) {
80 twoaday 32 SetDlgItemText (dlg, IDC_DECRYPT_LISTINF,
81     _("Encrypted with the following public key(s)"));
82     CheckDlgButton (dlg, IDC_DECRYPT_HIDE, BST_CHECKED);
83 twoaday 2 }
84 twoaday 25 else if (c->gpg_cmd == GPG_CMD_SIGN)
85 twoaday 23 CheckDlgButton (dlg, IDC_DECRYPT_SIGN_HIDE, BST_CHECKED);
86 twoaday 24 res = gpgme_op_decrypt_result (c->gpg);
87     if (res != NULL && c->gpg_cmd == GPG_CMD_DECRYPT) {
88 twoaday 23 gpgme_recipient_t r;
89    
90 twoaday 25 /* XXX: not all ENCRYPT_TO entries are listed here. */
91 twoaday 23 for (r = res->recipients; r; r = r->next) {
92     get_pubkey (r->keyid, &key);
93     if (key) {
94     char *uid;
95 twoaday 24 id = key->uids->name;
96 twoaday 23 if (!id)
97 twoaday 2 id = _("Invalid User ID");
98 twoaday 23 uid = utf8_to_wincp (id, strlen (id));
99 twoaday 25 info = new char [32+strlen (uid)+1 + 4 + strlen (r->keyid)+1
100     + strlen (key->uids->email)+1];
101 twoaday 23 if (!info)
102     BUG (NULL);
103 twoaday 24 sprintf (info, "%s <%s> (%s, 0x%s)", uid, key->uids->email,
104 twoaday 23 get_key_pubalgo (r->pubkey_algo), r->keyid+8);
105     free (uid);
106 twoaday 24
107 twoaday 2 }
108 twoaday 23 else {
109 twoaday 25 info = new char [32 + strlen (r->keyid)+1 + 4];
110 twoaday 23 if (!info)
111     BUG (NULL);
112 twoaday 25 sprintf (info, _("Unknown key ID (%s, 0x%s)"),
113     get_key_pubalgo (r->pubkey_algo), r->keyid+8);
114 twoaday 23 }
115 twoaday 24 listbox_add_string (GetDlgItem (dlg, IDC_DECRYPT_LIST), info);
116 twoaday 25 free_if_alloc (info);
117 twoaday 2 }
118     }
119 twoaday 24 else if (c->gpg_cmd == GPG_CMD_DECRYPT)
120     EnableWindow (GetDlgItem (dlg, IDC_DECRYPT_LIST), FALSE);
121 twoaday 25 SetDlgItemText (dlg, c->gpg_cmd == GPG_CMD_DECRYPT?
122 twoaday 2 IDC_DECRYPT_PWDINFO : IDC_DECRYPT_SIGN_PWDINFO,
123 twoaday 26 c->bad_pwd? _("Bad passphrase; Enter passphrase again") :
124 twoaday 25 _("Please enter your passphrase"));
125 twoaday 24 if (c->gpg_cmd == GPG_CMD_DECRYPT) {
126     SetFocus (GetDlgItem (dlg, IDC_DECRYPT_PWD));
127 twoaday 25 if (res && !res->recipients) {
128     const char *s = _("Symmetric encryption.\n"
129     "%s encrypted data.");
130     const char *alg = get_symkey_algo (c->sym.sym_algo);
131     info = new char[strlen (s) + strlen (alg) + 2];
132     if (!info)
133     BUG (NULL);
134     sprintf (info, s, alg);
135     SetDlgItemText (dlg, IDC_DECRYPT_MSG, info);
136     free_if_alloc (info);
137     }
138 twoaday 24 else
139     SetDlgItemText (dlg, IDC_DECRYPT_MSG, c->info);
140 twoaday 2 }
141     else {
142 twoaday 24 SetFocus( GetDlgItem (dlg, IDC_DECRYPT_SIGN_PWD));
143     SetDlgItemText (dlg, IDC_DECRYPT_SIGN_MSG, c->info);
144 twoaday 2 }
145 twoaday 24 center_window (dlg, NULL);
146     SetForegroundWindow (dlg);
147     set_active_window (dlg);
148 twoaday 2 return FALSE;
149    
150     case WM_SYSCOMMAND:
151 twoaday 26 if (LOWORD (wparam) == SC_CLOSE) {
152 twoaday 32 SetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), "");
153 twoaday 2 c->cancel = 1;
154 twoaday 26 EndDialog (dlg, TRUE);
155 twoaday 2 }
156 twoaday 24 break;
157 twoaday 2
158     case WM_COMMAND:
159 twoaday 32 switch (HIWORD (wparam)) {
160 twoaday 2 case BN_CLICKED:
161 twoaday 32 if (LOWORD (wparam) == IDC_DECRYPT_HIDE
162     || LOWORD (wparam) == IDC_DECRYPT_SIGN_HIDE) {
163 twoaday 2 HWND hwnd;
164 twoaday 22 int hide = IsDlgButtonChecked (dlg, item_ctrl_id2 (c->gpg_cmd));
165     hwnd = GetDlgItem (dlg, item_ctrl_id (c->gpg_cmd));
166 twoaday 25 SendMessage (hwnd, EM_SETPASSWORDCHAR, hide? '*' : 0, 0);
167 twoaday 22 SetFocus (hwnd);
168 twoaday 2 }
169     }
170    
171 twoaday 4 switch (LOWORD (wparam)) {
172     case IDOK:
173 twoaday 32 /* XXX: the item is even cached when the passphrase is not
174     correct, which means that the user needs to delete all
175     cached entries to continue. */
176 twoaday 26 if (c->pwd)
177     burn_passphrase (&c->pwd);
178 twoaday 23 n = item_get_text_length (dlg, item_ctrl_id (c->gpg_cmd));
179     if (!n) {
180     c->pwd = new char[2];
181 twoaday 26 if (!c->pwd)
182     BUG (NULL);
183 twoaday 23 strcpy (c->pwd, "");
184     }
185     else {
186 twoaday 24 c->pwd = new char[n+2];
187 twoaday 23 if (!c->pwd)
188     BUG (NULL);
189 twoaday 24 GetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), c->pwd, n+1);
190 twoaday 23 }
191 twoaday 24 res = gpgme_op_decrypt_result (c->gpg);
192     if (!res)
193     res_sig = gpgme_op_sign_result (c->gpg);
194     if (reg_prefs.cache_time > 0 && !c->is_card &&
195     ((res && res->recipients) || (res_sig && res_sig->signatures))) {
196 twoaday 4 if (agent_get_cache (c->keyid, &item))
197     agent_unlock_cache_entry (&item);
198 twoaday 2 else
199 twoaday 4 agent_put_cache (c->keyid, c->pwd, reg_prefs.cache_time);
200 twoaday 2 }
201 twoaday 32 c->cancel = 0;
202 twoaday 4 EndDialog (dlg, TRUE);
203 twoaday 2 return TRUE;
204    
205     case IDCANCEL:
206 twoaday 32 SetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), "");
207 twoaday 2 c->cancel = 1;
208 twoaday 4 EndDialog (dlg, FALSE);
209 twoaday 2 return FALSE;
210     }
211     break;
212     }
213    
214     return FALSE;
215 twoaday 23 }
216 twoaday 2
217    
218 twoaday 23 /* Extract the main keyid from @pass_info.
219     Return value: long main keyid or NULL for an error. */
220     static const char*
221     parse_gpg_keyid (const char *pass_info)
222 twoaday 2 {
223     static char keyid[16+1];
224    
225 twoaday 26 /* XXX: check for leading alpha-chars? */
226 twoaday 23 if (strlen (pass_info) < 16)
227 twoaday 2 return NULL;
228     /* the format of the desc buffer looks like this:
229     request_keyid[16] main_keyid[16] keytype[1] keylength[4]
230     we use the main keyid to use only one cache entry. */
231 twoaday 23 strncpy (keyid, pass_info+17, 16);
232     keyid[16] = 0;
233 twoaday 2 return keyid;
234 twoaday 23 }
235 twoaday 2
236    
237 twoaday 23 /* Parse the information in @uid_hint and @pass_info to generate
238     a input message for the user in @desc. */
239 twoaday 26 static int
240 twoaday 23 parse_gpg_description (const char *uid_hint, const char *pass_info,
241     char *desc, int size)
242 twoaday 2 {
243 twoaday 23 gpgme_pubkey_algo_t algo;
244 twoaday 32 char usedkey[16+1];
245     char mainkey[16+1];
246 twoaday 23 char *uid, *p;
247     int n=0;
248 twoaday 2
249 twoaday 32 /* Each uid_hint contains a long key-ID so it is at least 16 bytes. */
250 twoaday 26 if (strlen (uid_hint) < 17) {
251     *desc = 0;
252     return -1;
253     }
254    
255 twoaday 23 while (p = strsep ((char**)&pass_info, " ")) {
256     switch (n++) {
257     case 0: strncpy (mainkey, p, 16); mainkey[16] = 0; break;
258     case 1: strncpy (usedkey, p, 16); usedkey[16] = 0; break;
259     case 2: algo = (gpgme_pubkey_algo_t)atol (p); break;
260 twoaday 2 }
261     }
262 twoaday 23 uid_hint += 16; /* skip keyid */
263     uid_hint += 1; /* space */
264 twoaday 2
265 twoaday 23 uid = utf8_to_wincp (uid_hint, strlen (uid_hint));
266 twoaday 2
267 twoaday 23 if (strcmp (usedkey, mainkey))
268     _snprintf (desc, size-1,
269 twoaday 2 _("You need a passphrase to unlock the secret key for\n"
270     "user: \"%s\"\n"
271     "%s key, ID %s (main key ID %s)\n"),
272 twoaday 23 uid, get_key_pubalgo (algo), usedkey+8, mainkey+8);
273     else if (!strcmp (usedkey, mainkey))
274     _snprintf (desc, size-1,
275 twoaday 2 _("You need a passphrase to unlock the secret key for\n"
276     "user: \"%s\"\n"
277     "%s key, ID %s\n"),
278 twoaday 23 uid, get_key_pubalgo (algo), usedkey+8);
279     free (uid);
280 twoaday 26 return 0;
281 twoaday 23 }
282 twoaday 2
283    
284 twoaday 28 /* Extract the serial number from the card ID @id and return it. */
285     const char*
286     extract_serial_no (const char *id)
287     {
288     static char buf[8];
289     char *p;
290    
291     p = strchr (id, '/');
292     if (!p)
293     return NULL;
294     strncpy (buf, id+(p-id)-6, 6);
295     return buf;
296     }
297    
298    
299 twoaday 23 /* Passphrase callback with the ability to support caching. */
300     gpgme_error_t
301     passphrase_cb (void *hook, const char *uid_hint,
302     const char *passphrase_info,
303     int prev_was_bad, int fd)
304     {
305     passphrase_cb_s *c = (passphrase_cb_s*)hook;
306 twoaday 24 HANDLE hd = (HANDLE)fd;
307 twoaday 23 void *item;
308     const char *keyid, *pass;
309 twoaday 24 DWORD n;
310 twoaday 23 int rc;
311 twoaday 2
312 twoaday 23 if (!c)
313     return gpg_error (GPG_ERR_INV_ARG);
314 twoaday 26 c->bad_pwd = prev_was_bad? 1 : 0;
315     if (prev_was_bad && !c->cancel) {
316     if (c->pwd)
317     burn_passphrase (&c->pwd);
318     agent_del_cache (c->keyid);
319     c->pwd_init = 1;
320     }
321 twoaday 2
322 twoaday 23 if (passphrase_info) {
323 twoaday 26 if (strlen (passphrase_info) < 16 &&
324 twoaday 32 !strstr (passphrase_info, "OPENPGP")) {
325     /* assume symetric encryption. */
326 twoaday 25 int n=2;
327     c->sym.sym_algo = atoi (passphrase_info);
328     if (c->sym.sym_algo > 9)
329     n++;
330     /* XXX: be more strict. */
331     c->sym.s2k_mode = atoi (passphrase_info+n);
332     c->sym.s2k_hash = atoi (passphrase_info+n+2);
333     }
334    
335 twoaday 23 keyid = parse_gpg_keyid (passphrase_info);
336 twoaday 24 pass = agent_get_cache (keyid+8, &item);
337 twoaday 23 if (pass) {
338     agent_unlock_cache_entry (&item);
339 twoaday 2 c->pwd_init = 0;
340 twoaday 24 if (!WriteFile (hd, pass, strlen (pass), &n, NULL))
341     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
342     if (!WriteFile (hd, "\n", 1, &n, NULL))
343     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
344 twoaday 23 return 0;
345 twoaday 2 }
346     }
347    
348 twoaday 23 if (c->pwd_init) {
349     if (keyid && strlen (keyid) == 16)
350     strcpy (c->keyid, keyid+8);
351    
352 twoaday 26 /* if @passphrase_info contains 'OPENPGP' we assume a smart card
353     has been used. */
354     if (strstr (passphrase_info, "OPENPGP")) {
355 twoaday 28 const char *s=passphrase_info;
356     while (s && *s && *s != 'D')
357     s++;
358 twoaday 23 _snprintf (c->info, sizeof c->info-1,
359     _("Please enter the PIN to unlock your secret card key\n"
360 twoaday 28 "Card: %s"), extract_serial_no (s));
361 twoaday 2 c->is_card = 1;
362     }
363 twoaday 23 else if (uid_hint)
364     parse_gpg_description (uid_hint, passphrase_info,
365     c->info, sizeof c->info - 1);
366     if (c->gpg_cmd == GPG_CMD_DECRYPT) {
367     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT,
368     (HWND)c->hwnd, passphrase_callback_proc,
369     (LPARAM)c);
370 twoaday 2 }
371 twoaday 23 else if (c->gpg_cmd == GPG_CMD_SIGN) {
372     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT_SIGN,
373     (HWND)c->hwnd, passphrase_callback_proc,
374     (LPARAM)c);
375 twoaday 2 }
376 twoaday 23 if (rc == -1) {
377 twoaday 32 if (!WriteFile (hd, "\n", 1, &n, NULL))
378     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
379 twoaday 26 return 0;
380 twoaday 2 }
381     c->pwd_init = 0;
382     }
383 twoaday 23 if (c->cancel) {
384 twoaday 32 if (!WriteFile (hd, "\n", 1, &n, NULL))
385     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
386 twoaday 26 return 0;
387 twoaday 23 }
388 twoaday 2
389 twoaday 24 WriteFile (hd, c->pwd, strlen (c->pwd), &n, NULL);
390     WriteFile (hd, "\n", 1, &n, NULL);
391 twoaday 23 return 0;
392     }
393 twoaday 2
394    
395 twoaday 23 /* Initialize the given passphrase callback @cb with the
396     used gpgme context @ctx, the command @cmd and a title
397     @title for the dialog. */
398     void
399     set_gpg_passphrase_cb (passphrase_cb_s *cb, gpgme_ctx_t ctx,
400     int cmd, HWND hwnd, const char *title)
401     {
402     memset (cb, 0, sizeof *cb);
403     cb->gpg_cmd = cmd;
404 twoaday 26 cb->bad_pwd = 0;
405 twoaday 23 cb->is_card = 0;
406     cb->cancel = 0;
407     cb->hwnd = hwnd;
408     cb->pwd_init = 1;
409     free_if_alloc (cb->title);
410     cb->title = m_strdup (title);
411     if (!cb->title)
412     BUG (NULL);
413     gpgme_set_passphrase_cb (ctx, passphrase_cb, cb);
414     cb->gpg = ctx;
415     }
416 twoaday 2
417 twoaday 23
418     /* Release a passphrase callback @ctx. */
419 twoaday 2 void
420 twoaday 23 release_gpg_passphrase_cb (passphrase_cb_s *ctx)
421 twoaday 2 {
422 twoaday 23 if (!ctx)
423     return;
424     sfree_if_alloc (ctx->pwd);
425     free_if_alloc (ctx->title);
426     }
427 twoaday 22
428 twoaday 26
429 twoaday 23 /* Simple check to measure passphrase (@pass) quality.
430     Return value: 0 on success. */
431 twoaday 22 int
432     check_passwd_quality (const char *pass, int strict)
433     {
434     int i, nd=0, nc=0, n;
435    
436     n = strlen (pass);
437     if (n < 8)
438     return -1;
439    
440     for (i=0; i < n; i++) {
441 twoaday 32 if (isdigit (pass[i]))
442     nd++;
443     if (isalpha (pass[i]))
444     nc++;
445 twoaday 22 }
446    
447 twoaday 32 /* check that the passphrase contains letters and numbers. */
448 twoaday 22 if (nd == n || nc == n)
449     return -1;
450    
451     return 0;
452     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26