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

Contents of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 47 - (show annotations)
Mon Oct 31 14:04:59 2005 UTC (19 years, 4 months ago) by werner
File size: 12836 byte(s)
Minor changes; compiles now but gettext is still missing.

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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26