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

Annotation of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (hide annotations)
Mon Oct 17 08:49:30 2005 UTC (19 years, 4 months ago) by twoaday
File size: 12503 byte(s)
More bug fixes all over the place.
See ChangeLog for details.

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 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 2 SetDlgItemText( dlg, IDC_DECRYPT_LISTINF,
81     _("Encrypted with the following public key(s)") );
82     CheckDlgButton( dlg, IDC_DECRYPT_HIDE, BST_CHECKED );
83     }
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     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     switch( HIWORD( wparam ) ) {
160     case BN_CLICKED:
161     if ( LOWORD( wparam ) == IDC_DECRYPT_HIDE
162     || LOWORD( wparam ) == IDC_DECRYPT_SIGN_HIDE ) {
163     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 2 /* fixme: 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 4 EndDialog (dlg, TRUE);
202 twoaday 2 return TRUE;
203    
204     case IDCANCEL:
205 twoaday 4 SetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), "" );
206 twoaday 2 c->cancel = 1;
207 twoaday 4 EndDialog (dlg, FALSE);
208 twoaday 2 return FALSE;
209     }
210     break;
211     }
212    
213     return FALSE;
214 twoaday 23 }
215 twoaday 2
216    
217 twoaday 23 /* Extract the main keyid from @pass_info.
218     Return value: long main keyid or NULL for an error. */
219     static const char*
220     parse_gpg_keyid (const char *pass_info)
221 twoaday 2 {
222     static char keyid[16+1];
223    
224 twoaday 26 /* XXX: check for leading alpha-chars? */
225 twoaday 23 if (strlen (pass_info) < 16)
226 twoaday 2 return NULL;
227     /* the format of the desc buffer looks like this:
228     request_keyid[16] main_keyid[16] keytype[1] keylength[4]
229     we use the main keyid to use only one cache entry. */
230 twoaday 23 strncpy (keyid, pass_info+17, 16);
231     keyid[16] = 0;
232 twoaday 2 return keyid;
233 twoaday 23 }
234 twoaday 2
235    
236 twoaday 23 /* Parse the information in @uid_hint and @pass_info to generate
237     a input message for the user in @desc. */
238 twoaday 26 static int
239 twoaday 23 parse_gpg_description (const char *uid_hint, const char *pass_info,
240     char *desc, int size)
241 twoaday 2 {
242 twoaday 23 gpgme_pubkey_algo_t algo;
243     char usedkey[16+1], mainkey[16+1];
244     char *uid, *p;
245     int n=0;
246 twoaday 2
247 twoaday 26 if (strlen (uid_hint) < 17) {
248     *desc = 0;
249     return -1;
250     }
251    
252 twoaday 23 while (p = strsep ((char**)&pass_info, " ")) {
253     switch (n++) {
254     case 0: strncpy (mainkey, p, 16); mainkey[16] = 0; break;
255     case 1: strncpy (usedkey, p, 16); usedkey[16] = 0; break;
256     case 2: algo = (gpgme_pubkey_algo_t)atol (p); break;
257 twoaday 2 }
258     }
259 twoaday 23 uid_hint += 16; /* skip keyid */
260     uid_hint += 1; /* space */
261 twoaday 2
262 twoaday 23 uid = utf8_to_wincp (uid_hint, strlen (uid_hint));
263 twoaday 2
264 twoaday 23 if (strcmp (usedkey, mainkey))
265     _snprintf (desc, size-1,
266 twoaday 2 _("You need a passphrase to unlock the secret key for\n"
267     "user: \"%s\"\n"
268     "%s key, ID %s (main key ID %s)\n"),
269 twoaday 23 uid, get_key_pubalgo (algo), usedkey+8, mainkey+8);
270     else if (!strcmp (usedkey, mainkey))
271     _snprintf (desc, size-1,
272 twoaday 2 _("You need a passphrase to unlock the secret key for\n"
273     "user: \"%s\"\n"
274     "%s key, ID %s\n"),
275 twoaday 23 uid, get_key_pubalgo (algo), usedkey+8);
276     free (uid);
277 twoaday 26 return 0;
278 twoaday 23 }
279 twoaday 2
280    
281 twoaday 26 /*
282 twoaday 2 static int inline
283 twoaday 23 is_hexstring (const char * p)
284 twoaday 2 {
285     size_t i;
286 twoaday 23
287     for (i=0; i < strlen (p); i++) {
288     if (!isxdigit (p[i]))
289 twoaday 2 return -1;
290     }
291     return 0;
292     }
293 twoaday 26 */
294 twoaday 2
295 twoaday 23 /* Passphrase callback with the ability to support caching. */
296     gpgme_error_t
297     passphrase_cb (void *hook, const char *uid_hint,
298     const char *passphrase_info,
299     int prev_was_bad, int fd)
300     {
301     passphrase_cb_s *c = (passphrase_cb_s*)hook;
302 twoaday 24 HANDLE hd = (HANDLE)fd;
303 twoaday 23 void *item;
304     const char *keyid, *pass;
305 twoaday 24 DWORD n;
306 twoaday 23 int rc;
307 twoaday 2
308 twoaday 23 if (!c)
309     return gpg_error (GPG_ERR_INV_ARG);
310 twoaday 26 c->bad_pwd = prev_was_bad? 1 : 0;
311     if (prev_was_bad && !c->cancel) {
312     if (c->pwd)
313     burn_passphrase (&c->pwd);
314     agent_del_cache (c->keyid);
315     c->pwd_init = 1;
316     }
317 twoaday 2
318 twoaday 23 if (passphrase_info) {
319 twoaday 26 if (strlen (passphrase_info) < 16 &&
320     !strstr (passphrase_info, "OPENPGP")) {/* assume symetric encryption. */
321 twoaday 25 int n=2;
322     c->sym.sym_algo = atoi (passphrase_info);
323     if (c->sym.sym_algo > 9)
324     n++;
325     /* XXX: be more strict. */
326     c->sym.s2k_mode = atoi (passphrase_info+n);
327     c->sym.s2k_hash = atoi (passphrase_info+n+2);
328     }
329    
330 twoaday 23 keyid = parse_gpg_keyid (passphrase_info);
331 twoaday 24 pass = agent_get_cache (keyid+8, &item);
332 twoaday 23 if (pass) {
333     agent_unlock_cache_entry (&item);
334 twoaday 2 c->pwd_init = 0;
335 twoaday 24 if (!WriteFile (hd, pass, strlen (pass), &n, NULL))
336     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
337     if (!WriteFile (hd, "\n", 1, &n, NULL))
338     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
339 twoaday 23 return 0;
340 twoaday 2 }
341     }
342    
343 twoaday 23 if (c->pwd_init) {
344     if (keyid && strlen (keyid) == 16)
345     strcpy (c->keyid, keyid+8);
346    
347 twoaday 26 /* if @passphrase_info contains 'OPENPGP' we assume a smart card
348     has been used. */
349     if (strstr (passphrase_info, "OPENPGP")) {
350 twoaday 2 char buf[16];
351 twoaday 23 memset (buf, 0, sizeof buf);
352 twoaday 26 strncpy (buf, "??", 2); /* XXX: fixme we need the serial no. */
353 twoaday 23 _snprintf (c->info, sizeof c->info-1,
354     _("Please enter the PIN to unlock your secret card key\n"
355     "Card: %s"), buf);
356 twoaday 2 c->is_card = 1;
357     }
358 twoaday 23 else if (uid_hint)
359     parse_gpg_description (uid_hint, passphrase_info,
360     c->info, sizeof c->info - 1);
361     if (c->gpg_cmd == GPG_CMD_DECRYPT) {
362     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT,
363     (HWND)c->hwnd, passphrase_callback_proc,
364     (LPARAM)c);
365 twoaday 2 }
366 twoaday 23 else if (c->gpg_cmd == GPG_CMD_SIGN) {
367     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT_SIGN,
368     (HWND)c->hwnd, passphrase_callback_proc,
369     (LPARAM)c);
370 twoaday 2 }
371 twoaday 23 if (rc == -1) {
372 twoaday 24 WriteFile (hd, "\n", 1, &n, NULL);
373 twoaday 26 return 0;
374 twoaday 2 }
375     c->pwd_init = 0;
376     }
377 twoaday 23 if (c->cancel) {
378 twoaday 24 WriteFile (hd, "\n", 1, &n, NULL);
379 twoaday 26 return 0;
380 twoaday 23 }
381 twoaday 2
382 twoaday 24 WriteFile (hd, c->pwd, strlen (c->pwd), &n, NULL);
383     WriteFile (hd, "\n", 1, &n, NULL);
384 twoaday 23 return 0;
385     }
386 twoaday 2
387    
388 twoaday 23 /* Initialize the given passphrase callback @cb with the
389     used gpgme context @ctx, the command @cmd and a title
390     @title for the dialog. */
391     void
392     set_gpg_passphrase_cb (passphrase_cb_s *cb, gpgme_ctx_t ctx,
393     int cmd, HWND hwnd, const char *title)
394     {
395     memset (cb, 0, sizeof *cb);
396     cb->gpg_cmd = cmd;
397 twoaday 26 cb->bad_pwd = 0;
398 twoaday 23 cb->is_card = 0;
399     cb->cancel = 0;
400     cb->hwnd = hwnd;
401     cb->pwd_init = 1;
402     free_if_alloc (cb->title);
403     cb->title = m_strdup (title);
404     if (!cb->title)
405     BUG (NULL);
406     gpgme_set_passphrase_cb (ctx, passphrase_cb, cb);
407     cb->gpg = ctx;
408     }
409 twoaday 2
410 twoaday 23
411     /* Release a passphrase callback @ctx. */
412 twoaday 2 void
413 twoaday 23 release_gpg_passphrase_cb (passphrase_cb_s *ctx)
414 twoaday 2 {
415 twoaday 23 if (!ctx)
416     return;
417     sfree_if_alloc (ctx->pwd);
418     free_if_alloc (ctx->title);
419     }
420 twoaday 22
421 twoaday 26
422 twoaday 23 /* Simple check to measure passphrase (@pass) quality.
423     Return value: 0 on success. */
424 twoaday 22 int
425     check_passwd_quality (const char *pass, int strict)
426     {
427     int i, nd=0, nc=0, n;
428    
429     n = strlen (pass);
430     if (n < 8)
431     return -1;
432    
433     for (i=0; i < n; i++) {
434     if (isdigit (pass[i])) nd++;
435     if (isalpha (pass[i])) nc++;
436     }
437    
438     if (nd == n || nc == n)
439     return -1;
440    
441     return 0;
442     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26