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

Annotation of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26