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

Annotation of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 25 - (hide annotations)
Wed Oct 12 10:04:26 2005 UTC (19 years, 4 months ago) by twoaday
File size: 11991 byte(s)
First testing phase finished.
Provide bug fixes for a lot of (minor) problems.

1 twoaday 2 /* wptPassphraseCB.cpp - GPGME Passphrase Callback
2 twoaday 23 * Copyright (C) 2001, 2002, 2003, 2005 Timo Schulz
3 twoaday 24 * Copyright (C) 2005 g10 Code GmbH
4 twoaday 2 *
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 twoaday 23 #include "wptKeyList.h"
37 twoaday 2 #include "wptAgent.h"
38     #include "wptRegistry.h"
39    
40 twoaday 25 const char* get_symkey_algo (int algo);
41 twoaday 2
42     #define item_ctrl_id( cmd ) \
43     ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_PWD : IDC_DECRYPT_SIGN_PWD)
44    
45 twoaday 22 #define item_ctrl_id2(cmd) \
46     ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_HIDE : IDC_DECRYPT_SIGN_HIDE)
47 twoaday 2
48 twoaday 22
49 twoaday 23 /* Dialog procedure for the passphrase callback. */
50     static BOOL CALLBACK
51 twoaday 4 passphrase_callback_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
52 twoaday 2 {
53     static passphrase_cb_s * c;
54 twoaday 24 gpgme_decrypt_result_t res;
55     gpgme_sign_result_t res_sig;
56 twoaday 2 gpgme_key_t key;
57 twoaday 25 void *ctx = NULL, *item;
58 twoaday 23 const char *id;
59     char *info;
60     int n;
61 twoaday 2
62 twoaday 24 switch (msg) {
63 twoaday 2 case WM_INITDIALOG:
64     c = (passphrase_cb_s *)lparam;
65 twoaday 4 if (!c)
66     BUG (0);
67     SetWindowText (dlg, c->title);
68     if (c->gpg_cmd == GPG_CMD_DECRYPT) {
69 twoaday 2 SetDlgItemText( dlg, IDC_DECRYPT_LISTINF,
70     _("Encrypted with the following public key(s)") );
71     CheckDlgButton( dlg, IDC_DECRYPT_HIDE, BST_CHECKED );
72     }
73 twoaday 25 else if (c->gpg_cmd == GPG_CMD_SIGN)
74 twoaday 23 CheckDlgButton (dlg, IDC_DECRYPT_SIGN_HIDE, BST_CHECKED);
75 twoaday 24 res = gpgme_op_decrypt_result (c->gpg);
76     if (res != NULL && c->gpg_cmd == GPG_CMD_DECRYPT) {
77 twoaday 23 gpgme_recipient_t r;
78    
79 twoaday 25 /* XXX: not all ENCRYPT_TO entries are listed here. */
80 twoaday 23 for (r = res->recipients; r; r = r->next) {
81     get_pubkey (r->keyid, &key);
82     if (key) {
83     char *uid;
84 twoaday 24 id = key->uids->name;
85 twoaday 23 if (!id)
86 twoaday 2 id = _("Invalid User ID");
87 twoaday 23 uid = utf8_to_wincp (id, strlen (id));
88 twoaday 25 info = new char [32+strlen (uid)+1 + 4 + strlen (r->keyid)+1
89     + strlen (key->uids->email)+1];
90 twoaday 23 if (!info)
91     BUG (NULL);
92 twoaday 24 sprintf (info, "%s <%s> (%s, 0x%s)", uid, key->uids->email,
93 twoaday 23 get_key_pubalgo (r->pubkey_algo), r->keyid+8);
94     free (uid);
95 twoaday 24
96 twoaday 2 }
97 twoaday 23 else {
98 twoaday 25 info = new char [32 + strlen (r->keyid)+1 + 4];
99 twoaday 23 if (!info)
100     BUG (NULL);
101 twoaday 25 sprintf (info, _("Unknown key ID (%s, 0x%s)"),
102     get_key_pubalgo (r->pubkey_algo), r->keyid+8);
103 twoaday 23 }
104 twoaday 24 listbox_add_string (GetDlgItem (dlg, IDC_DECRYPT_LIST), info);
105 twoaday 25 free_if_alloc (info);
106 twoaday 2 }
107     }
108 twoaday 24 else if (c->gpg_cmd == GPG_CMD_DECRYPT)
109     EnableWindow (GetDlgItem (dlg, IDC_DECRYPT_LIST), FALSE);
110 twoaday 25 SetDlgItemText (dlg, c->gpg_cmd == GPG_CMD_DECRYPT?
111 twoaday 2 IDC_DECRYPT_PWDINFO : IDC_DECRYPT_SIGN_PWDINFO,
112 twoaday 25 _("Please enter your passphrase"));
113 twoaday 24 if (c->gpg_cmd == GPG_CMD_DECRYPT) {
114     SetFocus (GetDlgItem (dlg, IDC_DECRYPT_PWD));
115 twoaday 25 if (res && !res->recipients) {
116     const char *s = _("Symmetric encryption.\n"
117     "%s encrypted data.");
118     const char *alg = get_symkey_algo (c->sym.sym_algo);
119     info = new char[strlen (s) + strlen (alg) + 2];
120     if (!info)
121     BUG (NULL);
122     sprintf (info, s, alg);
123     SetDlgItemText (dlg, IDC_DECRYPT_MSG, info);
124     free_if_alloc (info);
125     }
126 twoaday 24 else
127     SetDlgItemText (dlg, IDC_DECRYPT_MSG, c->info);
128 twoaday 2 }
129     else {
130 twoaday 24 SetFocus( GetDlgItem (dlg, IDC_DECRYPT_SIGN_PWD));
131     SetDlgItemText (dlg, IDC_DECRYPT_SIGN_MSG, c->info);
132 twoaday 2 }
133 twoaday 24 center_window (dlg, NULL);
134     SetForegroundWindow (dlg);
135     set_active_window (dlg);
136 twoaday 2 return FALSE;
137    
138     case WM_SYSCOMMAND:
139     if( LOWORD( wparam ) == SC_CLOSE ) {
140     SetDlgItemText( dlg, item_ctrl_id( c->gpg_cmd ), "" );
141     c->cancel = 1;
142     EndDialog( dlg, TRUE );
143     }
144 twoaday 24 break;
145 twoaday 2
146     case WM_COMMAND:
147     switch( HIWORD( wparam ) ) {
148     case BN_CLICKED:
149     if ( LOWORD( wparam ) == IDC_DECRYPT_HIDE
150     || LOWORD( wparam ) == IDC_DECRYPT_SIGN_HIDE ) {
151     HWND hwnd;
152 twoaday 22 int hide = IsDlgButtonChecked (dlg, item_ctrl_id2 (c->gpg_cmd));
153     hwnd = GetDlgItem (dlg, item_ctrl_id (c->gpg_cmd));
154 twoaday 25 SendMessage (hwnd, EM_SETPASSWORDCHAR, hide? '*' : 0, 0);
155 twoaday 22 SetFocus (hwnd);
156 twoaday 2 }
157     }
158    
159 twoaday 4 switch (LOWORD (wparam)) {
160     case IDOK:
161 twoaday 2 /* fixme: the item is even cached when the passphrase is not
162     correct, which means that the user needs to delete all
163     cached entries to continue. */
164 twoaday 23 if (c->pwd) {
165     delete []c->pwd;
166     c->pwd = NULL;
167     }
168     n = item_get_text_length (dlg, item_ctrl_id (c->gpg_cmd));
169     if (!n) {
170     c->pwd = new char[2];
171     strcpy (c->pwd, "");
172     }
173     else {
174 twoaday 24 c->pwd = new char[n+2];
175 twoaday 23 if (!c->pwd)
176     BUG (NULL);
177 twoaday 24 GetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), c->pwd, n+1);
178 twoaday 23 }
179 twoaday 24 res = gpgme_op_decrypt_result (c->gpg);
180     if (!res)
181     res_sig = gpgme_op_sign_result (c->gpg);
182     if (reg_prefs.cache_time > 0 && !c->is_card &&
183     ((res && res->recipients) || (res_sig && res_sig->signatures))) {
184 twoaday 4 if (agent_get_cache (c->keyid, &item))
185     agent_unlock_cache_entry (&item);
186 twoaday 2 else
187 twoaday 4 agent_put_cache (c->keyid, c->pwd, reg_prefs.cache_time);
188 twoaday 2 }
189 twoaday 4 EndDialog (dlg, TRUE);
190 twoaday 2 return TRUE;
191    
192     case IDCANCEL:
193 twoaday 4 SetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), "" );
194 twoaday 2 c->cancel = 1;
195 twoaday 4 EndDialog (dlg, FALSE);
196 twoaday 2 return FALSE;
197     }
198     break;
199     }
200    
201     return FALSE;
202 twoaday 23 }
203 twoaday 2
204    
205 twoaday 23 /* Extract the main keyid from @pass_info.
206     Return value: long main keyid or NULL for an error. */
207     static const char*
208     parse_gpg_keyid (const char *pass_info)
209 twoaday 2 {
210     static char keyid[16+1];
211    
212 twoaday 23 if (strlen (pass_info) < 16)
213 twoaday 2 return NULL;
214     /* the format of the desc buffer looks like this:
215     request_keyid[16] main_keyid[16] keytype[1] keylength[4]
216     we use the main keyid to use only one cache entry. */
217 twoaday 23 strncpy (keyid, pass_info+17, 16);
218     keyid[16] = 0;
219 twoaday 2 return keyid;
220 twoaday 23 }
221 twoaday 2
222    
223 twoaday 23 /* Parse the information in @uid_hint and @pass_info to generate
224     a input message for the user in @desc. */
225 twoaday 2 static void
226 twoaday 23 parse_gpg_description (const char *uid_hint, const char *pass_info,
227     char *desc, int size)
228 twoaday 2 {
229 twoaday 23 gpgme_pubkey_algo_t algo;
230     char usedkey[16+1], mainkey[16+1];
231     char *uid, *p;
232     int n=0;
233 twoaday 2
234 twoaday 23 while (p = strsep ((char**)&pass_info, " ")) {
235     switch (n++) {
236     case 0: strncpy (mainkey, p, 16); mainkey[16] = 0; break;
237     case 1: strncpy (usedkey, p, 16); usedkey[16] = 0; break;
238     case 2: algo = (gpgme_pubkey_algo_t)atol (p); break;
239 twoaday 2 }
240     }
241 twoaday 23 uid_hint += 16; /* skip keyid */
242     uid_hint += 1; /* space */
243 twoaday 2
244 twoaday 23 uid = utf8_to_wincp (uid_hint, strlen (uid_hint));
245 twoaday 2
246 twoaday 23 if (strcmp (usedkey, mainkey))
247     _snprintf (desc, size-1,
248 twoaday 2 _("You need a passphrase to unlock the secret key for\n"
249     "user: \"%s\"\n"
250     "%s key, ID %s (main key ID %s)\n"),
251 twoaday 23 uid, get_key_pubalgo (algo), usedkey+8, mainkey+8);
252     else if (!strcmp (usedkey, mainkey))
253     _snprintf (desc, size-1,
254 twoaday 2 _("You need a passphrase to unlock the secret key for\n"
255     "user: \"%s\"\n"
256     "%s key, ID %s\n"),
257 twoaday 23 uid, get_key_pubalgo (algo), usedkey+8);
258     free (uid);
259     }
260 twoaday 2
261    
262     static int inline
263 twoaday 23 is_hexstring (const char * p)
264 twoaday 2 {
265     size_t i;
266 twoaday 23
267     for (i=0; i < strlen (p); i++) {
268     if (!isxdigit (p[i]))
269 twoaday 2 return -1;
270     }
271     return 0;
272     }
273    
274    
275 twoaday 23 /* Passphrase callback with the ability to support caching. */
276     gpgme_error_t
277     passphrase_cb (void *hook, const char *uid_hint,
278     const char *passphrase_info,
279     int prev_was_bad, int fd)
280     {
281     passphrase_cb_s *c = (passphrase_cb_s*)hook;
282 twoaday 24 HANDLE hd = (HANDLE)fd;
283 twoaday 23 void *item;
284     const char *keyid, *pass;
285 twoaday 24 DWORD n;
286 twoaday 23 int rc;
287 twoaday 2
288 twoaday 24 /* XXX: pubkey_enc cancel does not quit gpg.exe */
289     /* XXX: handle prev_was_bad case. */
290 twoaday 23 if (!c)
291     return gpg_error (GPG_ERR_INV_ARG);
292 twoaday 2
293 twoaday 23 if (passphrase_info) {
294 twoaday 25 if (strlen (passphrase_info) < 16) {/* assume symetric encryption. */
295     int n=2;
296     c->sym.sym_algo = atoi (passphrase_info);
297     if (c->sym.sym_algo > 9)
298     n++;
299     /* XXX: be more strict. */
300     c->sym.s2k_mode = atoi (passphrase_info+n);
301     c->sym.s2k_hash = atoi (passphrase_info+n+2);
302     }
303    
304 twoaday 23 keyid = parse_gpg_keyid (passphrase_info);
305 twoaday 24 pass = agent_get_cache (keyid+8, &item);
306 twoaday 23 if (pass) {
307     agent_unlock_cache_entry (&item);
308 twoaday 2 c->pwd_init = 0;
309 twoaday 24 if (!WriteFile (hd, pass, strlen (pass), &n, NULL))
310     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
311     if (!WriteFile (hd, "\n", 1, &n, NULL))
312     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
313 twoaday 23 return 0;
314 twoaday 2 }
315     }
316    
317 twoaday 23 if (c->pwd_init) {
318     if (keyid && strlen (keyid) == 16)
319     strcpy (c->keyid, keyid+8);
320    
321 twoaday 2 /* if the desc has a length of 32 and only hex digits, we assume a
322     smart card has been used. */
323 twoaday 23 if (uid_hint && strlen (uid_hint) == 32 && !is_hexstring (uid_hint)) {
324 twoaday 2 char buf[16];
325 twoaday 23 memset (buf, 0, sizeof buf);
326     strncpy (buf, uid_hint+20, 8);
327     _snprintf (c->info, sizeof c->info-1,
328     _("Please enter the PIN to unlock your secret card key\n"
329     "Card: %s"), buf);
330 twoaday 2 c->is_card = 1;
331     }
332 twoaday 23 else if (uid_hint)
333     parse_gpg_description (uid_hint, passphrase_info,
334     c->info, sizeof c->info - 1);
335     if (c->gpg_cmd == GPG_CMD_DECRYPT) {
336     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT,
337     (HWND)c->hwnd, passphrase_callback_proc,
338     (LPARAM)c);
339 twoaday 2 }
340 twoaday 23 else if (c->gpg_cmd == GPG_CMD_SIGN) {
341     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT_SIGN,
342     (HWND)c->hwnd, passphrase_callback_proc,
343     (LPARAM)c);
344 twoaday 2 }
345 twoaday 23 if (rc == -1) {
346 twoaday 24 WriteFile (hd, "\n", 1, &n, NULL);
347 twoaday 23 return gpg_error (GPG_ERR_EOF);
348 twoaday 2 }
349     c->pwd_init = 0;
350     }
351 twoaday 23 if (c->cancel) {
352 twoaday 24 WriteFile (hd, "\n", 1, &n, NULL);
353 twoaday 23 return gpg_error (GPG_ERR_EOF);
354     }
355 twoaday 2
356 twoaday 24 WriteFile (hd, c->pwd, strlen (c->pwd), &n, NULL);
357     WriteFile (hd, "\n", 1, &n, NULL);
358 twoaday 23 return 0;
359     }
360 twoaday 2
361    
362 twoaday 23 /* Initialize the given passphrase callback @cb with the
363     used gpgme context @ctx, the command @cmd and a title
364     @title for the dialog. */
365     void
366     set_gpg_passphrase_cb (passphrase_cb_s *cb, gpgme_ctx_t ctx,
367     int cmd, HWND hwnd, const char *title)
368     {
369     memset (cb, 0, sizeof *cb);
370     cb->gpg_cmd = cmd;
371     cb->is_card = 0;
372     cb->cancel = 0;
373     cb->hwnd = hwnd;
374     cb->pwd_init = 1;
375     free_if_alloc (cb->title);
376     cb->title = m_strdup (title);
377     if (!cb->title)
378     BUG (NULL);
379     gpgme_set_passphrase_cb (ctx, passphrase_cb, cb);
380     cb->gpg = ctx;
381     }
382 twoaday 2
383 twoaday 23
384     /* Release a passphrase callback @ctx. */
385 twoaday 2 void
386 twoaday 23 release_gpg_passphrase_cb (passphrase_cb_s *ctx)
387 twoaday 2 {
388 twoaday 23 if (!ctx)
389     return;
390     sfree_if_alloc (ctx->pwd);
391     free_if_alloc (ctx->title);
392     }
393 twoaday 22
394 twoaday 23 /* Simple check to measure passphrase (@pass) quality.
395     Return value: 0 on success. */
396 twoaday 22 int
397     check_passwd_quality (const char *pass, int strict)
398     {
399     int i, nd=0, nc=0, n;
400    
401     n = strlen (pass);
402     if (n < 8)
403     return -1;
404    
405     for (i=0; i < n; i++) {
406     if (isdigit (pass[i])) nd++;
407     if (isalpha (pass[i])) nc++;
408     }
409    
410     if (nd == n || nc == n)
411     return -1;
412    
413     return 0;
414     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26