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

Annotation of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 27 - (hide annotations)
Tue Oct 18 07:57:13 2005 UTC (19 years, 4 months ago) by twoaday
File size: 12567 byte(s)
Some bug fixes and adjustments for the latest
GPGME changes.

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     char *pass = *pwd;
54     memset (pass, 0, strlen (pass));
55     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 27 /* XXX: we need a timer to update the 'enc_to' entries. */
74 twoaday 24 switch (msg) {
75 twoaday 2 case WM_INITDIALOG:
76     c = (passphrase_cb_s *)lparam;
77 twoaday 4 if (!c)
78     BUG (0);
79     SetWindowText (dlg, c->title);
80     if (c->gpg_cmd == GPG_CMD_DECRYPT) {
81 twoaday 2 SetDlgItemText( dlg, IDC_DECRYPT_LISTINF,
82     _("Encrypted with the following public key(s)") );
83     CheckDlgButton( dlg, IDC_DECRYPT_HIDE, BST_CHECKED );
84     }
85 twoaday 25 else if (c->gpg_cmd == GPG_CMD_SIGN)
86 twoaday 23 CheckDlgButton (dlg, IDC_DECRYPT_SIGN_HIDE, BST_CHECKED);
87 twoaday 24 res = gpgme_op_decrypt_result (c->gpg);
88     if (res != NULL && c->gpg_cmd == GPG_CMD_DECRYPT) {
89 twoaday 23 gpgme_recipient_t r;
90    
91 twoaday 25 /* XXX: not all ENCRYPT_TO entries are listed here. */
92 twoaday 23 for (r = res->recipients; r; r = r->next) {
93     get_pubkey (r->keyid, &key);
94     if (key) {
95     char *uid;
96 twoaday 24 id = key->uids->name;
97 twoaday 23 if (!id)
98 twoaday 2 id = _("Invalid User ID");
99 twoaday 23 uid = utf8_to_wincp (id, strlen (id));
100 twoaday 25 info = new char [32+strlen (uid)+1 + 4 + strlen (r->keyid)+1
101     + strlen (key->uids->email)+1];
102 twoaday 23 if (!info)
103     BUG (NULL);
104 twoaday 24 sprintf (info, "%s <%s> (%s, 0x%s)", uid, key->uids->email,
105 twoaday 23 get_key_pubalgo (r->pubkey_algo), r->keyid+8);
106     free (uid);
107 twoaday 24
108 twoaday 2 }
109 twoaday 23 else {
110 twoaday 25 info = new char [32 + strlen (r->keyid)+1 + 4];
111 twoaday 23 if (!info)
112     BUG (NULL);
113 twoaday 25 sprintf (info, _("Unknown key ID (%s, 0x%s)"),
114     get_key_pubalgo (r->pubkey_algo), r->keyid+8);
115 twoaday 23 }
116 twoaday 24 listbox_add_string (GetDlgItem (dlg, IDC_DECRYPT_LIST), info);
117 twoaday 25 free_if_alloc (info);
118 twoaday 2 }
119     }
120 twoaday 24 else if (c->gpg_cmd == GPG_CMD_DECRYPT)
121     EnableWindow (GetDlgItem (dlg, IDC_DECRYPT_LIST), FALSE);
122 twoaday 25 SetDlgItemText (dlg, c->gpg_cmd == GPG_CMD_DECRYPT?
123 twoaday 2 IDC_DECRYPT_PWDINFO : IDC_DECRYPT_SIGN_PWDINFO,
124 twoaday 26 c->bad_pwd? _("Bad passphrase; Enter passphrase again") :
125 twoaday 25 _("Please enter your passphrase"));
126 twoaday 24 if (c->gpg_cmd == GPG_CMD_DECRYPT) {
127     SetFocus (GetDlgItem (dlg, IDC_DECRYPT_PWD));
128 twoaday 25 if (res && !res->recipients) {
129     const char *s = _("Symmetric encryption.\n"
130     "%s encrypted data.");
131     const char *alg = get_symkey_algo (c->sym.sym_algo);
132     info = new char[strlen (s) + strlen (alg) + 2];
133     if (!info)
134     BUG (NULL);
135     sprintf (info, s, alg);
136     SetDlgItemText (dlg, IDC_DECRYPT_MSG, info);
137     free_if_alloc (info);
138     }
139 twoaday 24 else
140     SetDlgItemText (dlg, IDC_DECRYPT_MSG, c->info);
141 twoaday 2 }
142     else {
143 twoaday 24 SetFocus( GetDlgItem (dlg, IDC_DECRYPT_SIGN_PWD));
144     SetDlgItemText (dlg, IDC_DECRYPT_SIGN_MSG, c->info);
145 twoaday 2 }
146 twoaday 24 center_window (dlg, NULL);
147     SetForegroundWindow (dlg);
148     set_active_window (dlg);
149 twoaday 2 return FALSE;
150    
151     case WM_SYSCOMMAND:
152 twoaday 26 if (LOWORD (wparam) == SC_CLOSE) {
153     SetDlgItemText (dlg, item_ctrl_id( c->gpg_cmd ), "");
154 twoaday 2 c->cancel = 1;
155 twoaday 26 EndDialog (dlg, TRUE);
156 twoaday 2 }
157 twoaday 24 break;
158 twoaday 2
159     case WM_COMMAND:
160     switch( HIWORD( wparam ) ) {
161     case BN_CLICKED:
162     if ( LOWORD( wparam ) == IDC_DECRYPT_HIDE
163     || LOWORD( wparam ) == IDC_DECRYPT_SIGN_HIDE ) {
164     HWND hwnd;
165 twoaday 22 int hide = IsDlgButtonChecked (dlg, item_ctrl_id2 (c->gpg_cmd));
166     hwnd = GetDlgItem (dlg, item_ctrl_id (c->gpg_cmd));
167 twoaday 25 SendMessage (hwnd, EM_SETPASSWORDCHAR, hide? '*' : 0, 0);
168 twoaday 22 SetFocus (hwnd);
169 twoaday 2 }
170     }
171    
172 twoaday 4 switch (LOWORD (wparam)) {
173     case IDOK:
174 twoaday 2 /* fixme: the item is even cached when the passphrase is not
175     correct, which means that the user needs to delete all
176     cached entries to continue. */
177 twoaday 26 if (c->pwd)
178     burn_passphrase (&c->pwd);
179 twoaday 23 n = item_get_text_length (dlg, item_ctrl_id (c->gpg_cmd));
180     if (!n) {
181     c->pwd = new char[2];
182 twoaday 26 if (!c->pwd)
183     BUG (NULL);
184 twoaday 23 strcpy (c->pwd, "");
185     }
186     else {
187 twoaday 24 c->pwd = new char[n+2];
188 twoaday 23 if (!c->pwd)
189     BUG (NULL);
190 twoaday 24 GetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), c->pwd, n+1);
191 twoaday 23 }
192 twoaday 24 res = gpgme_op_decrypt_result (c->gpg);
193     if (!res)
194     res_sig = gpgme_op_sign_result (c->gpg);
195     if (reg_prefs.cache_time > 0 && !c->is_card &&
196     ((res && res->recipients) || (res_sig && res_sig->signatures))) {
197 twoaday 4 if (agent_get_cache (c->keyid, &item))
198     agent_unlock_cache_entry (&item);
199 twoaday 2 else
200 twoaday 4 agent_put_cache (c->keyid, c->pwd, reg_prefs.cache_time);
201 twoaday 2 }
202 twoaday 4 EndDialog (dlg, TRUE);
203 twoaday 2 return TRUE;
204    
205     case IDCANCEL:
206 twoaday 4 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     char usedkey[16+1], mainkey[16+1];
245     char *uid, *p;
246     int n=0;
247 twoaday 2
248 twoaday 26 if (strlen (uid_hint) < 17) {
249     *desc = 0;
250     return -1;
251     }
252    
253 twoaday 23 while (p = strsep ((char**)&pass_info, " ")) {
254     switch (n++) {
255     case 0: strncpy (mainkey, p, 16); mainkey[16] = 0; break;
256     case 1: strncpy (usedkey, p, 16); usedkey[16] = 0; break;
257     case 2: algo = (gpgme_pubkey_algo_t)atol (p); break;
258 twoaday 2 }
259     }
260 twoaday 23 uid_hint += 16; /* skip keyid */
261     uid_hint += 1; /* space */
262 twoaday 2
263 twoaday 23 uid = utf8_to_wincp (uid_hint, strlen (uid_hint));
264 twoaday 2
265 twoaday 23 if (strcmp (usedkey, mainkey))
266     _snprintf (desc, size-1,
267 twoaday 2 _("You need a passphrase to unlock the secret key for\n"
268     "user: \"%s\"\n"
269     "%s key, ID %s (main key ID %s)\n"),
270 twoaday 23 uid, get_key_pubalgo (algo), usedkey+8, mainkey+8);
271     else if (!strcmp (usedkey, mainkey))
272     _snprintf (desc, size-1,
273 twoaday 2 _("You need a passphrase to unlock the secret key for\n"
274     "user: \"%s\"\n"
275     "%s key, ID %s\n"),
276 twoaday 23 uid, get_key_pubalgo (algo), usedkey+8);
277     free (uid);
278 twoaday 26 return 0;
279 twoaday 23 }
280 twoaday 2
281    
282 twoaday 26 /*
283 twoaday 2 static int inline
284 twoaday 23 is_hexstring (const char * p)
285 twoaday 2 {
286     size_t i;
287 twoaday 23
288     for (i=0; i < strlen (p); i++) {
289     if (!isxdigit (p[i]))
290 twoaday 2 return -1;
291     }
292     return 0;
293     }
294 twoaday 26 */
295 twoaday 2
296 twoaday 23 /* Passphrase callback with the ability to support caching. */
297     gpgme_error_t
298     passphrase_cb (void *hook, const char *uid_hint,
299     const char *passphrase_info,
300     int prev_was_bad, int fd)
301     {
302     passphrase_cb_s *c = (passphrase_cb_s*)hook;
303 twoaday 24 HANDLE hd = (HANDLE)fd;
304 twoaday 23 void *item;
305     const char *keyid, *pass;
306 twoaday 24 DWORD n;
307 twoaday 23 int rc;
308 twoaday 2
309 twoaday 23 if (!c)
310     return gpg_error (GPG_ERR_INV_ARG);
311 twoaday 26 c->bad_pwd = prev_was_bad? 1 : 0;
312     if (prev_was_bad && !c->cancel) {
313     if (c->pwd)
314     burn_passphrase (&c->pwd);
315     agent_del_cache (c->keyid);
316     c->pwd_init = 1;
317     }
318 twoaday 2
319 twoaday 23 if (passphrase_info) {
320 twoaday 26 if (strlen (passphrase_info) < 16 &&
321     !strstr (passphrase_info, "OPENPGP")) {/* assume symetric encryption. */
322 twoaday 25 int n=2;
323     c->sym.sym_algo = atoi (passphrase_info);
324     if (c->sym.sym_algo > 9)
325     n++;
326     /* XXX: be more strict. */
327     c->sym.s2k_mode = atoi (passphrase_info+n);
328     c->sym.s2k_hash = atoi (passphrase_info+n+2);
329     }
330    
331 twoaday 23 keyid = parse_gpg_keyid (passphrase_info);
332 twoaday 24 pass = agent_get_cache (keyid+8, &item);
333 twoaday 23 if (pass) {
334     agent_unlock_cache_entry (&item);
335 twoaday 2 c->pwd_init = 0;
336 twoaday 24 if (!WriteFile (hd, pass, strlen (pass), &n, NULL))
337     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
338     if (!WriteFile (hd, "\n", 1, &n, NULL))
339     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
340 twoaday 23 return 0;
341 twoaday 2 }
342     }
343    
344 twoaday 23 if (c->pwd_init) {
345     if (keyid && strlen (keyid) == 16)
346     strcpy (c->keyid, keyid+8);
347    
348 twoaday 26 /* if @passphrase_info contains 'OPENPGP' we assume a smart card
349     has been used. */
350     if (strstr (passphrase_info, "OPENPGP")) {
351 twoaday 2 char buf[16];
352 twoaday 23 memset (buf, 0, sizeof buf);
353 twoaday 26 strncpy (buf, "??", 2); /* XXX: fixme we need the serial no. */
354 twoaday 23 _snprintf (c->info, sizeof c->info-1,
355     _("Please enter the PIN to unlock your secret card key\n"
356     "Card: %s"), buf);
357 twoaday 2 c->is_card = 1;
358     }
359 twoaday 23 else if (uid_hint)
360     parse_gpg_description (uid_hint, passphrase_info,
361     c->info, sizeof c->info - 1);
362     if (c->gpg_cmd == GPG_CMD_DECRYPT) {
363     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT,
364     (HWND)c->hwnd, passphrase_callback_proc,
365     (LPARAM)c);
366 twoaday 2 }
367 twoaday 23 else if (c->gpg_cmd == GPG_CMD_SIGN) {
368     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT_SIGN,
369     (HWND)c->hwnd, passphrase_callback_proc,
370     (LPARAM)c);
371 twoaday 2 }
372 twoaday 23 if (rc == -1) {
373 twoaday 24 WriteFile (hd, "\n", 1, &n, NULL);
374 twoaday 26 return 0;
375 twoaday 2 }
376     c->pwd_init = 0;
377     }
378 twoaday 23 if (c->cancel) {
379 twoaday 24 WriteFile (hd, "\n", 1, &n, NULL);
380 twoaday 26 return 0;
381 twoaday 23 }
382 twoaday 2
383 twoaday 24 WriteFile (hd, c->pwd, strlen (c->pwd), &n, NULL);
384     WriteFile (hd, "\n", 1, &n, NULL);
385 twoaday 23 return 0;
386     }
387 twoaday 2
388    
389 twoaday 23 /* Initialize the given passphrase callback @cb with the
390     used gpgme context @ctx, the command @cmd and a title
391     @title for the dialog. */
392     void
393     set_gpg_passphrase_cb (passphrase_cb_s *cb, gpgme_ctx_t ctx,
394     int cmd, HWND hwnd, const char *title)
395     {
396     memset (cb, 0, sizeof *cb);
397     cb->gpg_cmd = cmd;
398 twoaday 26 cb->bad_pwd = 0;
399 twoaday 23 cb->is_card = 0;
400     cb->cancel = 0;
401     cb->hwnd = hwnd;
402     cb->pwd_init = 1;
403     free_if_alloc (cb->title);
404     cb->title = m_strdup (title);
405     if (!cb->title)
406     BUG (NULL);
407     gpgme_set_passphrase_cb (ctx, passphrase_cb, cb);
408     cb->gpg = ctx;
409     }
410 twoaday 2
411 twoaday 23
412     /* Release a passphrase callback @ctx. */
413 twoaday 2 void
414 twoaday 23 release_gpg_passphrase_cb (passphrase_cb_s *ctx)
415 twoaday 2 {
416 twoaday 23 if (!ctx)
417     return;
418     sfree_if_alloc (ctx->pwd);
419     free_if_alloc (ctx->title);
420     }
421 twoaday 22
422 twoaday 26
423 twoaday 23 /* Simple check to measure passphrase (@pass) quality.
424     Return value: 0 on success. */
425 twoaday 22 int
426     check_passwd_quality (const char *pass, int strict)
427     {
428     int i, nd=0, nc=0, n;
429    
430     n = strlen (pass);
431     if (n < 8)
432     return -1;
433    
434     for (i=0; i < n; i++) {
435     if (isdigit (pass[i])) nd++;
436     if (isalpha (pass[i])) nc++;
437     }
438    
439     if (nd == n || nc == n)
440     return -1;
441    
442     return 0;
443     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26