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

Contents of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 48 - (show annotations)
Mon Oct 31 21:14:11 2005 UTC (19 years, 4 months ago) by werner
File size: 12817 byte(s)
More changes.  Compiles again but there are at least gettext issues with
w32-gettext.c.  I can't get a gpg-error build with ENABLE_NLS.

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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26