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

Contents of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 27 - (show 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 /* 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 #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 #include "wptKeyList.h"
37 #include "wptAgent.h"
38 #include "wptRegistry.h"
39
40 const char* get_symkey_algo (int algo);
41
42 #define item_ctrl_id( cmd ) \
43 ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_PWD : IDC_DECRYPT_SIGN_PWD)
44
45 #define item_ctrl_id2(cmd) \
46 ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_HIDE : IDC_DECRYPT_SIGN_HIDE)
47
48
49 /* 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 /* Dialog procedure for the passphrase callback. */
61 static BOOL CALLBACK
62 passphrase_callback_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
63 {
64 static passphrase_cb_s * c;
65 gpgme_decrypt_result_t res;
66 gpgme_sign_result_t res_sig;
67 gpgme_key_t key;
68 void *ctx = NULL, *item;
69 const char *id;
70 char *info;
71 int n;
72
73 /* XXX: we need a timer to update the 'enc_to' entries. */
74 switch (msg) {
75 case WM_INITDIALOG:
76 c = (passphrase_cb_s *)lparam;
77 if (!c)
78 BUG (0);
79 SetWindowText (dlg, c->title);
80 if (c->gpg_cmd == GPG_CMD_DECRYPT) {
81 SetDlgItemText( dlg, IDC_DECRYPT_LISTINF,
82 _("Encrypted with the following public key(s)") );
83 CheckDlgButton( dlg, IDC_DECRYPT_HIDE, BST_CHECKED );
84 }
85 else if (c->gpg_cmd == GPG_CMD_SIGN)
86 CheckDlgButton (dlg, IDC_DECRYPT_SIGN_HIDE, BST_CHECKED);
87 res = gpgme_op_decrypt_result (c->gpg);
88 if (res != NULL && c->gpg_cmd == GPG_CMD_DECRYPT) {
89 gpgme_recipient_t r;
90
91 /* XXX: not all ENCRYPT_TO entries are listed here. */
92 for (r = res->recipients; r; r = r->next) {
93 get_pubkey (r->keyid, &key);
94 if (key) {
95 char *uid;
96 id = key->uids->name;
97 if (!id)
98 id = _("Invalid User ID");
99 uid = utf8_to_wincp (id, strlen (id));
100 info = new char [32+strlen (uid)+1 + 4 + strlen (r->keyid)+1
101 + strlen (key->uids->email)+1];
102 if (!info)
103 BUG (NULL);
104 sprintf (info, "%s <%s> (%s, 0x%s)", uid, key->uids->email,
105 get_key_pubalgo (r->pubkey_algo), r->keyid+8);
106 free (uid);
107
108 }
109 else {
110 info = new char [32 + strlen (r->keyid)+1 + 4];
111 if (!info)
112 BUG (NULL);
113 sprintf (info, _("Unknown key ID (%s, 0x%s)"),
114 get_key_pubalgo (r->pubkey_algo), r->keyid+8);
115 }
116 listbox_add_string (GetDlgItem (dlg, IDC_DECRYPT_LIST), info);
117 free_if_alloc (info);
118 }
119 }
120 else if (c->gpg_cmd == GPG_CMD_DECRYPT)
121 EnableWindow (GetDlgItem (dlg, IDC_DECRYPT_LIST), FALSE);
122 SetDlgItemText (dlg, c->gpg_cmd == GPG_CMD_DECRYPT?
123 IDC_DECRYPT_PWDINFO : IDC_DECRYPT_SIGN_PWDINFO,
124 c->bad_pwd? _("Bad passphrase; Enter passphrase again") :
125 _("Please enter your passphrase"));
126 if (c->gpg_cmd == GPG_CMD_DECRYPT) {
127 SetFocus (GetDlgItem (dlg, IDC_DECRYPT_PWD));
128 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 else
140 SetDlgItemText (dlg, IDC_DECRYPT_MSG, c->info);
141 }
142 else {
143 SetFocus( GetDlgItem (dlg, IDC_DECRYPT_SIGN_PWD));
144 SetDlgItemText (dlg, IDC_DECRYPT_SIGN_MSG, c->info);
145 }
146 center_window (dlg, NULL);
147 SetForegroundWindow (dlg);
148 set_active_window (dlg);
149 return FALSE;
150
151 case WM_SYSCOMMAND:
152 if (LOWORD (wparam) == SC_CLOSE) {
153 SetDlgItemText (dlg, item_ctrl_id( c->gpg_cmd ), "");
154 c->cancel = 1;
155 EndDialog (dlg, TRUE);
156 }
157 break;
158
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 int hide = IsDlgButtonChecked (dlg, item_ctrl_id2 (c->gpg_cmd));
166 hwnd = GetDlgItem (dlg, item_ctrl_id (c->gpg_cmd));
167 SendMessage (hwnd, EM_SETPASSWORDCHAR, hide? '*' : 0, 0);
168 SetFocus (hwnd);
169 }
170 }
171
172 switch (LOWORD (wparam)) {
173 case IDOK:
174 /* 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 if (c->pwd)
178 burn_passphrase (&c->pwd);
179 n = item_get_text_length (dlg, item_ctrl_id (c->gpg_cmd));
180 if (!n) {
181 c->pwd = new char[2];
182 if (!c->pwd)
183 BUG (NULL);
184 strcpy (c->pwd, "");
185 }
186 else {
187 c->pwd = new char[n+2];
188 if (!c->pwd)
189 BUG (NULL);
190 GetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), c->pwd, n+1);
191 }
192 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 if (agent_get_cache (c->keyid, &item))
198 agent_unlock_cache_entry (&item);
199 else
200 agent_put_cache (c->keyid, c->pwd, reg_prefs.cache_time);
201 }
202 EndDialog (dlg, TRUE);
203 return TRUE;
204
205 case IDCANCEL:
206 SetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), "" );
207 c->cancel = 1;
208 EndDialog (dlg, FALSE);
209 return FALSE;
210 }
211 break;
212 }
213
214 return FALSE;
215 }
216
217
218 /* 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 {
223 static char keyid[16+1];
224
225 /* XXX: check for leading alpha-chars? */
226 if (strlen (pass_info) < 16)
227 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 strncpy (keyid, pass_info+17, 16);
232 keyid[16] = 0;
233 return keyid;
234 }
235
236
237 /* Parse the information in @uid_hint and @pass_info to generate
238 a input message for the user in @desc. */
239 static int
240 parse_gpg_description (const char *uid_hint, const char *pass_info,
241 char *desc, int size)
242 {
243 gpgme_pubkey_algo_t algo;
244 char usedkey[16+1], mainkey[16+1];
245 char *uid, *p;
246 int n=0;
247
248 if (strlen (uid_hint) < 17) {
249 *desc = 0;
250 return -1;
251 }
252
253 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 }
259 }
260 uid_hint += 16; /* skip keyid */
261 uid_hint += 1; /* space */
262
263 uid = utf8_to_wincp (uid_hint, strlen (uid_hint));
264
265 if (strcmp (usedkey, mainkey))
266 _snprintf (desc, size-1,
267 _("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 uid, get_key_pubalgo (algo), usedkey+8, mainkey+8);
271 else if (!strcmp (usedkey, mainkey))
272 _snprintf (desc, size-1,
273 _("You need a passphrase to unlock the secret key for\n"
274 "user: \"%s\"\n"
275 "%s key, ID %s\n"),
276 uid, get_key_pubalgo (algo), usedkey+8);
277 free (uid);
278 return 0;
279 }
280
281
282 /*
283 static int inline
284 is_hexstring (const char * p)
285 {
286 size_t i;
287
288 for (i=0; i < strlen (p); i++) {
289 if (!isxdigit (p[i]))
290 return -1;
291 }
292 return 0;
293 }
294 */
295
296 /* 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 HANDLE hd = (HANDLE)fd;
304 void *item;
305 const char *keyid, *pass;
306 DWORD n;
307 int rc;
308
309 if (!c)
310 return gpg_error (GPG_ERR_INV_ARG);
311 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
319 if (passphrase_info) {
320 if (strlen (passphrase_info) < 16 &&
321 !strstr (passphrase_info, "OPENPGP")) {/* assume symetric encryption. */
322 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 keyid = parse_gpg_keyid (passphrase_info);
332 pass = agent_get_cache (keyid+8, &item);
333 if (pass) {
334 agent_unlock_cache_entry (&item);
335 c->pwd_init = 0;
336 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 return 0;
341 }
342 }
343
344 if (c->pwd_init) {
345 if (keyid && strlen (keyid) == 16)
346 strcpy (c->keyid, keyid+8);
347
348 /* if @passphrase_info contains 'OPENPGP' we assume a smart card
349 has been used. */
350 if (strstr (passphrase_info, "OPENPGP")) {
351 char buf[16];
352 memset (buf, 0, sizeof buf);
353 strncpy (buf, "??", 2); /* XXX: fixme we need the serial no. */
354 _snprintf (c->info, sizeof c->info-1,
355 _("Please enter the PIN to unlock your secret card key\n"
356 "Card: %s"), buf);
357 c->is_card = 1;
358 }
359 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 }
367 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 }
372 if (rc == -1) {
373 WriteFile (hd, "\n", 1, &n, NULL);
374 return 0;
375 }
376 c->pwd_init = 0;
377 }
378 if (c->cancel) {
379 WriteFile (hd, "\n", 1, &n, NULL);
380 return 0;
381 }
382
383 WriteFile (hd, c->pwd, strlen (c->pwd), &n, NULL);
384 WriteFile (hd, "\n", 1, &n, NULL);
385 return 0;
386 }
387
388
389 /* 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 cb->bad_pwd = 0;
399 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
411
412 /* Release a passphrase callback @ctx. */
413 void
414 release_gpg_passphrase_cb (passphrase_cb_s *ctx)
415 {
416 if (!ctx)
417 return;
418 sfree_if_alloc (ctx->pwd);
419 free_if_alloc (ctx->title);
420 }
421
422
423 /* Simple check to measure passphrase (@pass) quality.
424 Return value: 0 on success. */
425 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