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

Annotation of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 340 - (hide annotations)
Sun Nov 27 13:15:07 2011 UTC (13 years, 3 months ago) by twoaday
File size: 14790 byte(s)


1 werner 36 /* wptPassphraseCB.cpp - GPGME Passphrase Callback
2 twoaday 328 * Copyright (C) 2001, 2002-2006, 2009 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     if (!c->is_card && reg_prefs.cache_time > 0 &&
205     (res || res_sig)) {
206     if (agent_get_cache (c->keyid, &item))
207     agent_unlock_cache_entry (&item);
208     else
209     agent_put_cache (c->keyid, c->pwd,
210     reg_prefs.cache_time);
211     }
212 werner 36 }
213     c->cancel = 0;
214     EndDialog (dlg, TRUE);
215     return TRUE;
216    
217     case IDCANCEL:
218     SetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), "");
219     c->cancel = 1;
220     EndDialog (dlg, FALSE);
221 twoaday 271 return TRUE;
222 werner 36 }
223     break;
224     }
225    
226     return FALSE;
227     }
228    
229    
230     /* Extract the main keyid from @pass_info.
231     Return value: long main keyid or NULL for an error. */
232     static const char*
233     parse_gpg_keyid (const char *pass_info)
234     {
235     static char keyid[16+1];
236    
237     /* XXX: check for leading alpha-chars? */
238 twoaday 77 if (strlen (pass_info) < 16) {
239     log_debug ("parse_gpg_keyid: error '%s'\r\n", pass_info);
240 werner 36 return NULL;
241 twoaday 77 }
242 werner 36 /* the format of the desc buffer looks like this:
243     request_keyid[16] main_keyid[16] keytype[1] keylength[4]
244     we use the main keyid to use only one cache entry. */
245     strncpy (keyid, pass_info+17, 16);
246     keyid[16] = 0;
247     return keyid;
248     }
249    
250    
251     /* Parse the information in @uid_hint and @pass_info to generate
252     a input message for the user in @desc. */
253     static int
254     parse_gpg_description (const char *uid_hint, const char *pass_info,
255 twoaday 328 char *desc, size_t desc_size)
256 werner 36 {
257     gpgme_pubkey_algo_t algo;
258     char usedkey[16+1];
259     char mainkey[16+1];
260 twoaday 205 char *p, *uid;
261 werner 36 int n=0;
262    
263 twoaday 69 algo = (gpgme_pubkey_algo_t)0;
264 werner 36 /* Each uid_hint contains a long key-ID so it is at least 16 bytes. */
265     if (strlen (uid_hint) < 17) {
266     *desc = 0;
267 twoaday 77 log_debug ("parse_gpg_description: error '%s'\r\n", uid_hint);
268 werner 36 return -1;
269     }
270    
271 twoaday 328 while ((p = strsep ((char**)&pass_info, " "))) {
272 werner 36 switch (n++) {
273 twoaday 328 case 0:
274     strncpy (mainkey, p, 16);
275     mainkey[16] = 0;
276     break;
277    
278     case 1:
279     strncpy (usedkey, p, 16);
280     usedkey[16] = 0;
281     break;
282    
283     case 2:
284     algo = (gpgme_pubkey_algo_t)atol (p);
285     break;
286 werner 36 }
287     }
288     uid_hint += 16; /* skip keyid */
289     uid_hint += 1; /* space */
290    
291 twoaday 333 struct winpt_key_s skey;
292     gpgme_subkey_t sk;
293     if (winpt_get_seckey (mainkey, &skey))
294     BUG (0);
295     for (sk = skey.ctx->subkeys; sk; sk = sk->next) {
296     if (memcmp (sk->keyid, usedkey, 8) == 0)
297     break;
298     }
299 twoaday 205 uid = utf8_to_native (uid_hint);
300 werner 36 if (strcmp (usedkey, mainkey))
301 twoaday 328 _snprintf (desc, desc_size-1,
302 twoaday 255 _("You need a passphrase to unlock the secret key for user:\n"
303     "\"%s\"\n"
304 twoaday 333 "%d-bit %s key, ID 0x%s, created %s (main key ID 0x%s)\n"),
305     uid, sk->length, get_key_pubalgo (algo),
306     usedkey+8, get_key_created (sk->timestamp), mainkey+8);
307 werner 36 else if (!strcmp (usedkey, mainkey))
308 twoaday 328 _snprintf (desc, desc_size-1,
309 twoaday 255 _("You need a passphrase to unlock the secret key for user:\n"
310     "\"%s\"\n"
311 twoaday 333 "%d-bit %s key, created %s, ID 0x%s\n"),
312     uid, sk->length, get_key_pubalgo (algo),
313     get_key_created (sk->timestamp), usedkey+8);
314 twoaday 205 safe_free (uid);
315 werner 36 return 0;
316     }
317    
318    
319     /* Extract the serial number from the card ID @id and return it. */
320     const char*
321     extract_serial_no (const char *id)
322     {
323     static char buf[8];
324     char *p;
325    
326     p = strchr (id, '/');
327 twoaday 77 if (!p) {
328     log_debug ("extract_serial_no: error '%s'\r\n", id);
329 twoaday 260 return "";
330 twoaday 77 }
331 twoaday 260 memset (buf, 0, sizeof (buf));
332 werner 36 strncpy (buf, id+(p-id)-6, 6);
333     return buf;
334     }
335    
336    
337     /* Passphrase callback with the ability to support caching. */
338     gpgme_error_t
339     passphrase_cb (void *hook, const char *uid_hint,
340     const char *passphrase_info,
341     int prev_was_bad, int fd)
342     {
343     passphrase_cb_s *c = (passphrase_cb_s*)hook;
344     HANDLE hd = (HANDLE)fd;
345     void *item;
346 twoaday 69 const char *keyid=NULL, *pass;
347 werner 36 DWORD n;
348    
349 twoaday 77 if (!c) {
350 twoaday 271 log_debug ("passphrase_cb: error no valid callback\r\n");
351 werner 36 return gpg_error (GPG_ERR_INV_ARG);
352 twoaday 77 }
353 twoaday 328
354     /* If the last entered passphrase was wrong, we delete a
355     possible cached entry, we reset the passphrase buffer
356     and switch to the initial state. */
357 werner 36 c->bad_pwd = prev_was_bad? 1 : 0;
358     if (prev_was_bad && !c->cancel) {
359     if (c->pwd)
360     burn_passphrase (&c->pwd);
361     agent_del_cache (c->keyid);
362     c->pwd_init = 1;
363     }
364    
365     if (passphrase_info) {
366     if (strlen (passphrase_info) < 16 &&
367     !strstr (passphrase_info, "OPENPGP")) {
368     /* assume symetric encryption. */
369 twoaday 69 int pos=2;
370 werner 36 c->sym.sym_algo = atoi (passphrase_info);
371     if (c->sym.sym_algo > 9)
372 twoaday 69 pos++;
373     c->sym.s2k_mode = atoi (passphrase_info+pos);
374     c->sym.s2k_hash = atoi (passphrase_info+pos+2);
375 werner 36 }
376    
377     keyid = parse_gpg_keyid (passphrase_info);
378 twoaday 77 pass = agent_get_cache (keyid+8, &item);
379 werner 36 if (pass) {
380     agent_unlock_cache_entry (&item);
381     c->pwd_init = 0;
382     if (!WriteFile (hd, pass, strlen (pass), &n, NULL))
383     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
384     if (!WriteFile (hd, "\n", 1, &n, NULL))
385     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
386     return 0;
387     }
388     }
389    
390     if (c->pwd_init) {
391     if (keyid && strlen (keyid) == 16)
392     strcpy (c->keyid, keyid+8);
393    
394     /* if @passphrase_info contains 'OPENPGP' we assume a smart card
395     has been used. */
396     if (strstr (passphrase_info, "OPENPGP")) {
397     const char *s=passphrase_info;
398     while (s && *s && *s != 'D')
399     s++;
400 twoaday 304 _snprintf (c->info, DIM (c->info)-1,
401 werner 36 _("Please enter the PIN to unlock your secret card key\n"
402     "Card: %s"), extract_serial_no (s));
403     c->is_card = 1;
404     }
405     else if (uid_hint)
406     parse_gpg_description (uid_hint, passphrase_info,
407 twoaday 328 c->info, DIM (c->info) - 1);
408     int rc = 0;
409 werner 36 if (c->gpg_cmd == GPG_CMD_DECRYPT) {
410     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT,
411     (HWND)c->hwnd, passphrase_callback_proc,
412     (LPARAM)c);
413     }
414     else if (c->gpg_cmd == GPG_CMD_SIGN) {
415     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT_SIGN,
416     (HWND)c->hwnd, passphrase_callback_proc,
417     (LPARAM)c);
418     }
419     if (rc == -1) {
420     if (!WriteFile (hd, "\n", 1, &n, NULL))
421     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
422 twoaday 271 log_debug ("passphrase_cb: could not create dialog box\n");
423 werner 36 return 0;
424     }
425     c->pwd_init = 0;
426     }
427 twoaday 214 if (c->cancel || !c->pwd) {
428 werner 36 if (!WriteFile (hd, "\n", 1, &n, NULL))
429     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
430     return 0;
431     }
432    
433 twoaday 77 if (!WriteFile (hd, c->pwd, strlen (c->pwd), &n, NULL))
434     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
435     if (!WriteFile (hd, "\n", 1, &n, NULL))
436     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
437 werner 36 return 0;
438     }
439    
440    
441     /* Initialize the given passphrase callback @cb with the
442     used gpgme context @ctx, the command @cmd and a title
443     @title for the dialog. */
444     void
445     set_gpg_passphrase_cb (passphrase_cb_s *cb, gpgme_ctx_t ctx,
446     int cmd, HWND hwnd, const char *title)
447 twoaday 328 {
448 werner 36 memset (cb, 0, sizeof *cb);
449     cb->gpg_cmd = cmd;
450     cb->bad_pwd = 0;
451     cb->is_card = 0;
452     cb->cancel = 0;
453     cb->hwnd = hwnd;
454     cb->pwd_init = 1;
455     cb->title = m_strdup (title);
456     gpgme_set_passphrase_cb (ctx, passphrase_cb, cb);
457     cb->gpg = ctx;
458     }
459    
460 twoaday 328 void
461     set_gpg_auto_passphrase_cb (passphrase_cb_s *cb, const char *title)
462     {
463     memset (cb, 0, sizeof *cb);
464     cb->gpg_cmd = GPG_CMD_SIGN;
465     cb->bad_pwd = 0;
466     cb->is_card = 0;
467     cb->cancel = 0;
468     cb->hwnd = GetActiveWindow ();
469     cb->pwd_init = 1;
470     cb->title = m_strdup (title);
471     }
472 werner 36
473 twoaday 328
474     /* Release a passphrase callback @ctx. */
475     void
476     release_gpg_passphrase_cb (passphrase_cb_s *ctx)
477     {
478     if (!ctx)
479     return;
480     sfree_if_alloc (ctx->pwd);
481     free_if_alloc (ctx->title);
482     release_gpg_recipients (&ctx->recipients);
483     }
484    
485    
486 twoaday 214 /* Release the gpg recipient list. */
487 werner 36 void
488 twoaday 214 release_gpg_recipients (gpgme_recipient_t *recipients)
489 werner 36 {
490     gpgme_recipient_t r, n;
491    
492 twoaday 214 r = *recipients;
493     while (r != NULL) {
494 werner 36 n = r->next;
495     safe_free (r->keyid);
496     safe_free (r);
497     r = n;
498     }
499 twoaday 214 *recipients = NULL;
500 werner 36 }
501    
502    
503 twoaday 271 /* _Simple_ check to measure passphrase (@pass) quality.
504 werner 36 Return value: 0 on success. */
505     int
506     check_passwd_quality (const char *pass, int strict)
507     {
508     int i, nd=0, nc=0, n;
509    
510 twoaday 271 /* A good passphrase should be at least 8 characters. */
511 werner 36 n = strlen (pass);
512     if (n < 8)
513     return -1;
514    
515     for (i=0; i < n; i++) {
516 twoaday 271 if (isdigit (pass[i]))
517 werner 36 nd++;
518 twoaday 271 if (isalpha (pass[i]))
519 werner 36 nc++;
520     }
521    
522 twoaday 271 /* Check that the passphrase contains letters and numbers. */
523 werner 36 if (nd == n || nc == n)
524     return -1;
525    
526     return 0;
527     }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26