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

Annotation of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 344 - (hide annotations)
Sun Nov 27 14:56:52 2011 UTC (13 years, 3 months ago) by twoaday
File size: 14834 byte(s)


1 werner 36 /* wptPassphraseCB.cpp - GPGME Passphrase Callback
2 twoaday 344 * Copyright (C) 2001, 2002-2006, 2009, 2011 Timo Schulz
3 werner 36 * 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     #ifdef HAVE_CONFIG_H
18     #include <config.h>
19     #endif
20    
21     #include <windows.h>
22     #include <ctype.h>
23    
24 werner 47 #include "resource.h"
25 werner 36 #include "wptNLS.h"
26     #include "wptW32API.h"
27     #include "wptVersion.h"
28     #include "wptGPG.h"
29     #include "wptCommonCtl.h"
30     #include "wptContext.h"
31     #include "wptDlgs.h"
32     #include "wptErrors.h"
33     #include "wptTypes.h"
34 werner 48 #include "wptKeylist.h"
35 werner 36 #include "wptAgent.h"
36     #include "wptRegistry.h"
37 twoaday 205 #include "wptUTF8.h"
38 twoaday 278 #include "StringBuffer.h"
39 werner 36
40    
41 twoaday 255 /* Return the control ID dependent on the mode (sign or decrypt). */
42 twoaday 181 #define item_ctrl_id(cmd) \
43 werner 36 ((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 twoaday 255 const char* get_symkey_algo (int algo);
49 twoaday 204
50 twoaday 255
51 twoaday 328 /* Overwrites the passphrase and free the memory.
52     Pointer is also reset to NULL. */
53 werner 36 static void
54     burn_passphrase (char **pwd)
55     {
56     char *pass = *pwd;
57 twoaday 271
58 werner 36 wipememory (pass, strlen (pass));
59     delete []pass;
60     *pwd = NULL;
61     }
62    
63    
64     /* Dialog procedure for the passphrase callback. */
65     static BOOL CALLBACK
66     passphrase_callback_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
67     {
68 twoaday 77 static passphrase_cb_s *c;
69     gpgme_decrypt_result_t res=NULL;
70     gpgme_sign_result_t res_sig=NULL;
71 twoaday 69 gpgme_recipient_t recip=NULL, r;
72 twoaday 217 winpt_key_s key;
73 twoaday 69 void *item;
74 werner 36 int n;
75    
76     switch (msg) {
77 twoaday 181 case WM_ACTIVATE:
78 twoaday 297 /* Some people complained that it is no longer possible to
79     paste in the passphrase in this dialog. When this option
80     is enabled, the ordinary passphrase control will be used. */
81     if (!reg_prefs.no_safe_pwd_ctrl)
82     safe_edit_control_init (dlg, item_ctrl_id (c->gpg_cmd));
83 twoaday 181 break;
84    
85     case WM_DESTROY:
86 twoaday 297 if (!reg_prefs.no_safe_pwd_ctrl)
87     safe_edit_control_free (dlg, item_ctrl_id (c->gpg_cmd));
88 twoaday 181 break;
89    
90 werner 36 case WM_INITDIALOG:
91     c = (passphrase_cb_s *)lparam;
92     if (!c)
93     BUG (0);
94 twoaday 105 SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
95 werner 36 SetWindowText (dlg, c->title);
96     if (c->gpg_cmd == GPG_CMD_DECRYPT) {
97 twoaday 214 SetDlgItemText (dlg, IDC_DECRYPT_HIDE, _("&Hide Typing"));
98 werner 36 SetDlgItemText (dlg, IDC_DECRYPT_LISTINF,
99 twoaday 328 _("Encrypted with the following public key(s):"));
100 werner 36 CheckDlgButton (dlg, IDC_DECRYPT_HIDE, BST_CHECKED);
101     }
102 twoaday 95 else if (c->gpg_cmd == GPG_CMD_SIGN) {
103     SetDlgItemText (dlg, IDC_DECRYPT_SIGN_HIDE, _("&Hide Typing"));
104 werner 36 CheckDlgButton (dlg, IDC_DECRYPT_SIGN_HIDE, BST_CHECKED);
105 twoaday 95 }
106 twoaday 179 /* Because it depends on the order the keys are stored in the
107 twoaday 328 keyring, whether res->recipients is complete or not, we also
108 twoaday 179 support that the recipients were externally extracted and then
109     we use this list. */
110 twoaday 328 if (c->recipients) /* recipients were already extracted. */
111     recip = c->recipients;
112     else if (c->gpg) {
113 werner 36 res = gpgme_op_decrypt_result (c->gpg);
114     if (res && res->recipients)
115     recip = res->recipients;
116     }
117     if (recip != NULL && c->gpg_cmd == GPG_CMD_DECRYPT) {
118 twoaday 278 StringBuffer inf;
119    
120 twoaday 179 for (r = recip; r; r = r->next) {
121 twoaday 217 memset (&key, 0, sizeof (key));
122     if (!winpt_get_pubkey (r->keyid, &key)) {
123     gpgme_user_id_t u = key.ctx->uids;
124 twoaday 278 inf = (u->name? u->name : _("Invalid User ID"));
125     if (u->email != NULL && strlen (u->email) > 1)
126     inf = inf + " <" + u->email + ">";
127     inf = inf + " (" + get_key_pubalgo (r->pubkey_algo);
128     inf = inf + ", 0x" + (r->keyid+8) + ")";
129 werner 36 }
130     else {
131 twoaday 278 inf = _("Unknown key ID");
132     inf = inf + " (" + get_key_pubalgo (r->pubkey_algo);
133     inf = inf + ", 0x" + (r->keyid+8) + ")";
134 werner 36 }
135 twoaday 278 ListBox_AddString_utf8 (GetDlgItem (dlg, IDC_DECRYPT_LIST),
136     inf.getBuffer ());
137 twoaday 217 winpt_release_pubkey (&key);
138 werner 36 }
139     }
140     else if (c->gpg_cmd == GPG_CMD_DECRYPT)
141     EnableWindow (GetDlgItem (dlg, IDC_DECRYPT_LIST), FALSE);
142     SetDlgItemText (dlg, c->gpg_cmd == GPG_CMD_DECRYPT?
143     IDC_DECRYPT_PWDINFO : IDC_DECRYPT_SIGN_PWDINFO,
144 twoaday 328 c->bad_pwd? _("Invalid passphrase; Please enter your passphrase again") :
145 werner 36 _("Please enter your passphrase"));
146     if (c->gpg_cmd == GPG_CMD_DECRYPT) {
147     SetFocus (GetDlgItem (dlg, IDC_DECRYPT_PWD));
148 twoaday 328 /* no recipients means symmetric encryption */
149     if (res && !res->recipients) {
150 twoaday 278 StringBuffer sinf;
151    
152     sinf = _("Symmetric encryption.");
153     sinf = sinf + "\n" + get_symkey_algo (c->sym.sym_algo);
154 twoaday 328 sinf = sinf + " " + _("encrypted data") + ".";
155 twoaday 278 SetDlgItemText (dlg, IDC_DECRYPT_MSG, sinf.getBuffer ());
156 werner 36 }
157     else
158 twoaday 205 SetDlgItemText (dlg, IDC_DECRYPT_MSG, c->info);
159 werner 36 }
160     else {
161 twoaday 204 SetFocus (GetDlgItem (dlg, IDC_DECRYPT_SIGN_PWD));
162 twoaday 205 SetDlgItemText (dlg, IDC_DECRYPT_SIGN_MSG, c->info);
163 werner 36 }
164     center_window (dlg, NULL);
165     SetForegroundWindow (dlg);
166     return FALSE;
167    
168     case WM_COMMAND:
169     switch (HIWORD (wparam)) {
170     case BN_CLICKED:
171 twoaday 328 if (LOWORD (wparam) == IDC_DECRYPT_HIDE ||
172     LOWORD (wparam) == IDC_DECRYPT_SIGN_HIDE) {
173 werner 36 HWND hwnd;
174 twoaday 328 int hide;
175     hide = IsDlgButtonChecked (dlg, item_ctrl_id2 (c->gpg_cmd));
176 werner 36 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 twoaday 328 case IDOK:
184 werner 36 /* 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     strcpy (c->pwd, "");
193     }
194     else {
195 twoaday 229 char *p = new char[n+2];
196     SafeGetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), p, n+1);
197 twoaday 340 c->pwd = m_strdup (p);
198 twoaday 229 sfree_if_alloc (p);
199 werner 36 }
200 twoaday 328 if (c->gpg != NULL) {
201     res = gpgme_op_decrypt_result (c->gpg);
202     if (!res)
203     res_sig = gpgme_op_sign_result (c->gpg);
204 twoaday 344 if (!c->is_card && reg_prefs.cache_time > 0 && (res || res_sig)) {
205 twoaday 328 if (agent_get_cache (c->keyid, &item))
206     agent_unlock_cache_entry (&item);
207     else
208 twoaday 344 agent_put_cache (c->keyid, c->pwd, reg_prefs.cache_time);
209 twoaday 328 }
210 werner 36 }
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 twoaday 271 return TRUE;
220 werner 36 }
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 twoaday 77 if (strlen (pass_info) < 16) {
237     log_debug ("parse_gpg_keyid: error '%s'\r\n", pass_info);
238 werner 36 return NULL;
239 twoaday 77 }
240 werner 36 /* the format of the desc buffer looks like this:
241     request_keyid[16] main_keyid[16] keytype[1] keylength[4]
242     we use the main keyid to use only one cache entry. */
243     strncpy (keyid, pass_info+17, 16);
244     keyid[16] = 0;
245     return keyid;
246     }
247    
248    
249     /* Parse the information in @uid_hint and @pass_info to generate
250     a input message for the user in @desc. */
251     static int
252     parse_gpg_description (const char *uid_hint, const char *pass_info,
253 twoaday 328 char *desc, size_t desc_size)
254 werner 36 {
255     gpgme_pubkey_algo_t algo;
256 twoaday 344 char usedkey[16 + 1];
257     char mainkey[16 + 1];
258     char *p;
259 werner 36
260 twoaday 69 algo = (gpgme_pubkey_algo_t)0;
261 werner 36 /* Each uid_hint contains a long key-ID so it is at least 16 bytes. */
262     if (strlen (uid_hint) < 17) {
263     *desc = 0;
264 twoaday 77 log_debug ("parse_gpg_description: error '%s'\r\n", uid_hint);
265 werner 36 return -1;
266     }
267    
268 twoaday 344 int n = 0;
269 twoaday 328 while ((p = strsep ((char**)&pass_info, " "))) {
270 werner 36 switch (n++) {
271 twoaday 328 case 0:
272     strncpy (mainkey, p, 16);
273     mainkey[16] = 0;
274     break;
275    
276     case 1:
277     strncpy (usedkey, p, 16);
278     usedkey[16] = 0;
279     break;
280    
281     case 2:
282     algo = (gpgme_pubkey_algo_t)atol (p);
283     break;
284 werner 36 }
285     }
286     uid_hint += 16; /* skip keyid */
287     uid_hint += 1; /* space */
288    
289 twoaday 333 struct winpt_key_s skey;
290     gpgme_subkey_t sk;
291     if (winpt_get_seckey (mainkey, &skey))
292     BUG (0);
293     for (sk = skey.ctx->subkeys; sk; sk = sk->next) {
294     if (memcmp (sk->keyid, usedkey, 8) == 0)
295     break;
296     }
297 twoaday 344 char *uid = utf8_to_native (uid_hint);
298 werner 36 if (strcmp (usedkey, mainkey))
299 twoaday 328 _snprintf (desc, desc_size-1,
300 twoaday 255 _("You need a passphrase to unlock the secret key for user:\n"
301     "\"%s\"\n"
302 twoaday 333 "%d-bit %s key, ID 0x%s, created %s (main key ID 0x%s)\n"),
303     uid, sk->length, get_key_pubalgo (algo),
304     usedkey+8, get_key_created (sk->timestamp), mainkey+8);
305 werner 36 else if (!strcmp (usedkey, mainkey))
306 twoaday 328 _snprintf (desc, desc_size-1,
307 twoaday 255 _("You need a passphrase to unlock the secret key for user:\n"
308     "\"%s\"\n"
309 twoaday 333 "%d-bit %s key, created %s, ID 0x%s\n"),
310     uid, sk->length, get_key_pubalgo (algo),
311     get_key_created (sk->timestamp), usedkey+8);
312 twoaday 205 safe_free (uid);
313 werner 36 return 0;
314     }
315    
316    
317     /* Extract the serial number from the card ID @id and return it. */
318     const char*
319     extract_serial_no (const char *id)
320     {
321     static char buf[8];
322     char *p;
323    
324     p = strchr (id, '/');
325 twoaday 77 if (!p) {
326     log_debug ("extract_serial_no: error '%s'\r\n", id);
327 twoaday 260 return "";
328 twoaday 77 }
329 twoaday 260 memset (buf, 0, sizeof (buf));
330 werner 36 strncpy (buf, id+(p-id)-6, 6);
331     return buf;
332     }
333    
334    
335     /* Passphrase callback with the ability to support caching. */
336     gpgme_error_t
337     passphrase_cb (void *hook, const char *uid_hint,
338     const char *passphrase_info,
339     int prev_was_bad, int fd)
340     {
341     passphrase_cb_s *c = (passphrase_cb_s*)hook;
342     HANDLE hd = (HANDLE)fd;
343     void *item;
344 twoaday 69 const char *keyid=NULL, *pass;
345 werner 36 DWORD n;
346    
347 twoaday 77 if (!c) {
348 twoaday 271 log_debug ("passphrase_cb: error no valid callback\r\n");
349 werner 36 return gpg_error (GPG_ERR_INV_ARG);
350 twoaday 77 }
351 twoaday 328
352     /* If the last entered passphrase was wrong, we delete a
353     possible cached entry, we reset the passphrase buffer
354     and switch to the initial state. */
355 werner 36 c->bad_pwd = prev_was_bad? 1 : 0;
356     if (prev_was_bad && !c->cancel) {
357     if (c->pwd)
358     burn_passphrase (&c->pwd);
359     agent_del_cache (c->keyid);
360     c->pwd_init = 1;
361     }
362    
363     if (passphrase_info) {
364     if (strlen (passphrase_info) < 16 &&
365     !strstr (passphrase_info, "OPENPGP")) {
366     /* assume symetric encryption. */
367 twoaday 344 int pos = 2;
368 werner 36 c->sym.sym_algo = atoi (passphrase_info);
369     if (c->sym.sym_algo > 9)
370 twoaday 69 pos++;
371     c->sym.s2k_mode = atoi (passphrase_info+pos);
372     c->sym.s2k_hash = atoi (passphrase_info+pos+2);
373 werner 36 }
374    
375     keyid = parse_gpg_keyid (passphrase_info);
376 twoaday 77 pass = agent_get_cache (keyid+8, &item);
377 werner 36 if (pass) {
378     agent_unlock_cache_entry (&item);
379     c->pwd_init = 0;
380     if (!WriteFile (hd, pass, strlen (pass), &n, NULL))
381     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
382     if (!WriteFile (hd, "\n", 1, &n, NULL))
383     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
384     return 0;
385     }
386     }
387    
388     if (c->pwd_init) {
389     if (keyid && strlen (keyid) == 16)
390     strcpy (c->keyid, keyid+8);
391    
392     /* if @passphrase_info contains 'OPENPGP' we assume a smart card
393     has been used. */
394     if (strstr (passphrase_info, "OPENPGP")) {
395     const char *s=passphrase_info;
396     while (s && *s && *s != 'D')
397     s++;
398 twoaday 304 _snprintf (c->info, DIM (c->info)-1,
399 werner 36 _("Please enter the PIN to unlock your secret card key\n"
400     "Card: %s"), extract_serial_no (s));
401     c->is_card = 1;
402     }
403     else if (uid_hint)
404     parse_gpg_description (uid_hint, passphrase_info,
405 twoaday 328 c->info, DIM (c->info) - 1);
406     int rc = 0;
407 werner 36 if (c->gpg_cmd == GPG_CMD_DECRYPT) {
408     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT,
409     (HWND)c->hwnd, passphrase_callback_proc,
410     (LPARAM)c);
411     }
412     else if (c->gpg_cmd == GPG_CMD_SIGN) {
413     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT_SIGN,
414     (HWND)c->hwnd, passphrase_callback_proc,
415     (LPARAM)c);
416     }
417     if (rc == -1) {
418     if (!WriteFile (hd, "\n", 1, &n, NULL))
419     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
420 twoaday 271 log_debug ("passphrase_cb: could not create dialog box\n");
421 werner 36 return 0;
422     }
423     c->pwd_init = 0;
424     }
425 twoaday 214 if (c->cancel || !c->pwd) {
426 werner 36 if (!WriteFile (hd, "\n", 1, &n, NULL))
427     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
428     return 0;
429     }
430    
431 twoaday 77 if (!WriteFile (hd, c->pwd, strlen (c->pwd), &n, NULL))
432     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
433     if (!WriteFile (hd, "\n", 1, &n, NULL))
434     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
435 werner 36 return 0;
436     }
437    
438    
439     /* Initialize the given passphrase callback @cb with the
440     used gpgme context @ctx, the command @cmd and a title
441     @title for the dialog. */
442     void
443     set_gpg_passphrase_cb (passphrase_cb_s *cb, gpgme_ctx_t ctx,
444     int cmd, HWND hwnd, const char *title)
445 twoaday 328 {
446 werner 36 memset (cb, 0, sizeof *cb);
447     cb->gpg_cmd = cmd;
448     cb->bad_pwd = 0;
449     cb->is_card = 0;
450     cb->cancel = 0;
451     cb->hwnd = hwnd;
452     cb->pwd_init = 1;
453     cb->title = m_strdup (title);
454     gpgme_set_passphrase_cb (ctx, passphrase_cb, cb);
455     cb->gpg = ctx;
456     }
457    
458 twoaday 328 void
459     set_gpg_auto_passphrase_cb (passphrase_cb_s *cb, const char *title)
460     {
461     memset (cb, 0, sizeof *cb);
462     cb->gpg_cmd = GPG_CMD_SIGN;
463     cb->bad_pwd = 0;
464     cb->is_card = 0;
465     cb->cancel = 0;
466     cb->hwnd = GetActiveWindow ();
467     cb->pwd_init = 1;
468     cb->title = m_strdup (title);
469     }
470 werner 36
471 twoaday 328
472     /* Release a passphrase callback @ctx. */
473     void
474     release_gpg_passphrase_cb (passphrase_cb_s *ctx)
475     {
476     if (!ctx)
477     return;
478     sfree_if_alloc (ctx->pwd);
479     free_if_alloc (ctx->title);
480     release_gpg_recipients (&ctx->recipients);
481     }
482    
483    
484 twoaday 214 /* Release the gpg recipient list. */
485 werner 36 void
486 twoaday 214 release_gpg_recipients (gpgme_recipient_t *recipients)
487 werner 36 {
488     gpgme_recipient_t r, n;
489    
490 twoaday 214 r = *recipients;
491     while (r != NULL) {
492 werner 36 n = r->next;
493     safe_free (r->keyid);
494     safe_free (r);
495     r = n;
496     }
497 twoaday 214 *recipients = NULL;
498 werner 36 }
499    
500    
501 twoaday 271 /* _Simple_ check to measure passphrase (@pass) quality.
502 werner 36 Return value: 0 on success. */
503     int
504     check_passwd_quality (const char *pass, int strict)
505     {
506 twoaday 344 size_t i, nd = 0, nc = 0, na = 0, n;
507 werner 36
508 twoaday 271 /* A good passphrase should be at least 8 characters. */
509 werner 36 n = strlen (pass);
510     if (n < 8)
511     return -1;
512    
513 twoaday 344 for (i = 0; i < n; i++) {
514 twoaday 271 if (isdigit (pass[i]))
515 werner 36 nd++;
516 twoaday 271 if (isalpha (pass[i]))
517 werner 36 nc++;
518 twoaday 344 else
519     na++;
520 werner 36 }
521    
522 twoaday 271 /* Check that the passphrase contains letters and numbers. */
523 twoaday 344 if (nd == n || nc == n || na == n)
524 werner 36 return -1;
525    
526     return 0;
527     }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26