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

Contents of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (show annotations)
Thu Oct 20 12:35:59 2005 UTC (19 years, 4 months ago) by twoaday
File size: 12819 byte(s)
Minor cleanups and prepare the translation.

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
297 /* Extract the serial number from the card ID @id and return it. */
298 const char*
299 extract_serial_no (const char *id)
300 {
301 static char buf[8];
302 char *p;
303
304 p = strchr (id, '/');
305 if (!p)
306 return NULL;
307 strncpy (buf, id+(p-id)-6, 6);
308 return buf;
309 }
310
311
312 /* Passphrase callback with the ability to support caching. */
313 gpgme_error_t
314 passphrase_cb (void *hook, const char *uid_hint,
315 const char *passphrase_info,
316 int prev_was_bad, int fd)
317 {
318 passphrase_cb_s *c = (passphrase_cb_s*)hook;
319 HANDLE hd = (HANDLE)fd;
320 void *item;
321 const char *keyid, *pass;
322 DWORD n;
323 int rc;
324
325 if (!c)
326 return gpg_error (GPG_ERR_INV_ARG);
327 c->bad_pwd = prev_was_bad? 1 : 0;
328 if (prev_was_bad && !c->cancel) {
329 if (c->pwd)
330 burn_passphrase (&c->pwd);
331 agent_del_cache (c->keyid);
332 c->pwd_init = 1;
333 }
334
335 if (passphrase_info) {
336 if (strlen (passphrase_info) < 16 &&
337 !strstr (passphrase_info, "OPENPGP")) {/* assume symetric encryption. */
338 int n=2;
339 c->sym.sym_algo = atoi (passphrase_info);
340 if (c->sym.sym_algo > 9)
341 n++;
342 /* XXX: be more strict. */
343 c->sym.s2k_mode = atoi (passphrase_info+n);
344 c->sym.s2k_hash = atoi (passphrase_info+n+2);
345 }
346
347 keyid = parse_gpg_keyid (passphrase_info);
348 pass = agent_get_cache (keyid+8, &item);
349 if (pass) {
350 agent_unlock_cache_entry (&item);
351 c->pwd_init = 0;
352 if (!WriteFile (hd, pass, strlen (pass), &n, NULL))
353 log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
354 if (!WriteFile (hd, "\n", 1, &n, NULL))
355 log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
356 return 0;
357 }
358 }
359
360 if (c->pwd_init) {
361 if (keyid && strlen (keyid) == 16)
362 strcpy (c->keyid, keyid+8);
363
364 /* if @passphrase_info contains 'OPENPGP' we assume a smart card
365 has been used. */
366 if (strstr (passphrase_info, "OPENPGP")) {
367 const char *s=passphrase_info;
368 while (s && *s && *s != 'D')
369 s++;
370 _snprintf (c->info, sizeof c->info-1,
371 _("Please enter the PIN to unlock your secret card key\n"
372 "Card: %s"), extract_serial_no (s));
373 c->is_card = 1;
374 }
375 else if (uid_hint)
376 parse_gpg_description (uid_hint, passphrase_info,
377 c->info, sizeof c->info - 1);
378 if (c->gpg_cmd == GPG_CMD_DECRYPT) {
379 rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT,
380 (HWND)c->hwnd, passphrase_callback_proc,
381 (LPARAM)c);
382 }
383 else if (c->gpg_cmd == GPG_CMD_SIGN) {
384 rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT_SIGN,
385 (HWND)c->hwnd, passphrase_callback_proc,
386 (LPARAM)c);
387 }
388 if (rc == -1) {
389 WriteFile (hd, "\n", 1, &n, NULL);
390 return 0;
391 }
392 c->pwd_init = 0;
393 }
394 if (c->cancel) {
395 WriteFile (hd, "\n", 1, &n, NULL);
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 if (!ctx)
433 return;
434 sfree_if_alloc (ctx->pwd);
435 free_if_alloc (ctx->title);
436 }
437
438
439 /* Simple check to measure passphrase (@pass) quality.
440 Return value: 0 on success. */
441 int
442 check_passwd_quality (const char *pass, int strict)
443 {
444 int i, nd=0, nc=0, n;
445
446 n = strlen (pass);
447 if (n < 8)
448 return -1;
449
450 for (i=0; i < n; i++) {
451 if (isdigit (pass[i])) nd++;
452 if (isalpha (pass[i])) nc++;
453 }
454
455 if (nd == n || nc == n)
456 return -1;
457
458 return 0;
459 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26