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

Contents of /trunk/Src/wptKeygenDlg.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 328 - (show annotations)
Fri Sep 25 16:07:38 2009 UTC (15 years, 5 months ago) by twoaday
File size: 17058 byte(s)


1 /* wptKeygenDlg.cpp - Key Generation dialog
2 * Copyright (C) 2000-2007, 2009 Timo Schulz
3 *
4 * This file is part of WinPT.
5 *
6 * WinPT is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * WinPT is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16 #ifdef HAVE_CONFIG_H
17 #include <config.h>
18 #endif
19
20 #include <windows.h>
21 #include <time.h>
22
23 #include "resource.h"
24 #include "wptTypes.h"
25 #include "wptNLS.h"
26 #include "wptGPG.h"
27 #include "wptCommonCtl.h"
28 #include "wptContext.h"
29 #include "wptDlgs.h"
30 #include "wptW32API.h"
31 #include "wptVersion.h"
32 #include "wptErrors.h"
33 #include "StringBuffer.h"
34
35
36 /* All valid key generation combination. */
37 enum gpg_keytype_t {
38 GPG_KEYGEN_NONE = 0,
39 GPG_KEYGEN_DSA_ELG = 1,
40 GPG_KEYGEN_DSA_RSA = 2,
41 GPG_KEYGEN_RSA_RSA = 3 /*PGP*/
42 };
43
44
45 /* Generate the GPG specific genkey params with the given information.
46 @keytype: See valid combinations.
47 @bits: Length in bits.
48 @user: user-ID name
49 @comment: comment for the user-ID.
50 @email: email address.
51 @expdata: date of expiration or NULL.
52 @passphrase: the actual passphrase.
53 Return value: the gen. params. */
54 static char*
55 gpg_genkey_params (int keytype, int bits,
56 const char *user, const char *comment, const char *email,
57 const char *expdate, const char *pass)
58 {
59 StringBuffer p;
60 char *param;
61
62 if (keytype == GPG_KEYGEN_NONE)
63 return NULL;
64
65 p = "<GnupgKeyParms format=\"internal\">\n";
66 /* In this phase we set the primary key information fields. */
67 switch (keytype) {
68 case GPG_KEYGEN_DSA_ELG:
69 case GPG_KEYGEN_DSA_RSA:
70 p = p + "Key-Type: DSA\n";
71 p = p + "Key-Usage: sign\n";
72 p = p + "Key-Length: 2048\n";
73 break;
74
75 case GPG_KEYGEN_RSA_RSA:
76 p = p + "Key-Type: RSA\n";
77 p = p + "Key-Usage: sign\n";
78 p = p + "Key-Length: " + (int)bits + "\n";
79 break;
80
81 default:
82 break;
83 }
84
85 /* The next phase is the subkey information if needed. */
86 if (keytype == GPG_KEYGEN_DSA_ELG || keytype == GPG_KEYGEN_DSA_RSA ||
87 keytype == GPG_KEYGEN_RSA_RSA) {
88 if (keytype == GPG_KEYGEN_DSA_ELG)
89 p = p + "Subkey-Type: ELG-E\n";
90 else if (keytype == GPG_KEYGEN_DSA_RSA || keytype == GPG_KEYGEN_RSA_RSA)
91 p = p + "Subkey-Type: RSA\n";
92 p = p + "Subkey-Usage: encrypt\n";
93 p = p + "Subkey-Length: " + (int)bits + "\n";
94 }
95
96 /* Followed by the user ID information. */
97 p = p + "Name-Real: " + user + "\n";
98 if (comment != NULL)
99 p = p + "Name-Comment: " + comment + "\n";
100 p = p + "Name-Email: " + email + "\n";
101
102 if (expdate != NULL)
103 p = p + "Expire-Date: " + expdate + "\n";
104 else
105 p = p + "Expire-Date: 0\n";
106 p = p + "Passphrase: " + pass + "\n";
107
108 p = p + "</GnupgKeyParms>\n";
109 param = p.getBufferCopy ();
110 p.wipeContents ();
111
112 return param;
113 }
114
115
116 /* Generate a key with the given params @params. @prog_cb is a user defined
117 progress callback which is called during the generation.
118 @fpr will store the fingerprint of the generated key.
119 Return value: 0 on success. */
120 gpgme_error_t
121 gpg_genkey (const char *params, gpgme_progress_cb_t prog_cb, char **fpr)
122 {
123 gpgme_error_t err;
124 gpgme_ctx_t ctx;
125 gpgme_genkey_result_t res;
126
127 err = gpgme_new(&ctx);
128 if (err)
129 return err;
130 if (prog_cb)
131 gpgme_set_progress_cb (ctx, prog_cb, NULL);
132 err = gpgme_op_genkey (ctx, params, NULL, NULL);
133 if (!err) {
134 res = gpgme_op_genkey_result (ctx);
135 *fpr = res && res->fpr? m_strdup (res->fpr) : NULL;
136 }
137 gpgme_release (ctx);
138 return err;
139 }
140
141
142
143 /* Reset all dialog fields to its initial value. */
144 static void
145 reset_dlg_fields (HWND dlg)
146 {
147 SetDlgItemText (dlg, IDC_KEYGEN_SUBKEYBITS, "");
148 SetDlgItemText (dlg, IDC_KEYGEN_NAME, "");
149 SetDlgItemText (dlg, IDC_KEYGEN_EMAIL, "");
150 SetDlgItemText (dlg, IDC_KEYGEN_COMMENT, "");
151 SetDlgItemText (dlg, IDC_KEYGEN_EXPDATE, "");
152 }
153
154
155 /* Ask the user if a keyring backup is wanted and if so,
156 backup both keyrings to the selected folder.
157 Return value: true on success. */
158 static bool
159 backup_keyrings (HWND dlg)
160 {
161 const char *name;
162 char *keyring;
163 char *path;
164 bool success = true;
165 int id;
166
167 id = msg_box (dlg,
168 _("It is STRONGLY recommend that you backup your keyrings because they both "
169 "contain VERY important data.\nRemember that your hard disk can crash or the "
170 "files can be deleted by accident; so it is a good\nidea to store them on "
171 "a different mass stoarge like a floppy or CDR!\n\n"
172 "Backup your keyrings now?"),
173 _("WARNING - Important hint" ), MB_YESNO);
174 if (id != IDYES)
175 return false;
176
177 path = get_gnupg_path ();
178 name = get_filesave_dlg (dlg, _("Destination for Public Keyring"),
179 NULL, "pubring_bak.gpg");
180 if (name != NULL) {
181 keyring = make_filename (path, "pubring", "gpg");
182 if (!CopyFile (keyring, name, FALSE)) {
183 log_box (_("Key Generation"), MB_ERR,
184 _("Could not copy %s -> %s"), keyring, name);
185 success = false;
186 }
187 free_if_alloc (keyring);
188 }
189
190 name = get_filesave_dlg (dlg, _("Destination for Secret Keyring"),
191 NULL, "secring_bak.gpg");
192 if (name != NULL) {
193 keyring = make_filename (path, "secring", "gpg");
194 if (!CopyFile (keyring, name, FALSE)) {
195 log_box (_("Key Generation"), MB_ERR,
196 _("Could not copy %s -> %s"), keyring, name);
197 success = false;
198 }
199 free_if_alloc (keyring);
200 }
201 free_if_alloc (path);
202 return success;
203 }
204
205
206 /* Fill in all valid GPG algorithms. */
207 static void
208 fill_keytype_box (HWND dlg)
209 {
210 HWND cb = GetDlgItem (dlg, IDC_KEYGEN_KEYTYPE);
211
212 #define addstr(cb, str) \
213 SendMessage ((cb), CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)(str))
214 addstr (cb, _("DSA and ELG"));
215 addstr (cb, _("DSA and RSA"));
216 addstr (cb, _("RSA and RSA (PGP)") );
217 SendMessage (cb, CB_SETCURSEL, 2, 0);
218 #undef addstr
219 }
220
221
222 time_t w32_mktime (SYSTEMTIME *st);
223
224 /* Check that the given date lies not in the past.
225 Return value: 1 on success. */
226 int
227 keygen_check_date (SYSTEMTIME *st)
228 {
229 time_t date, now;
230
231 date = w32_mktime (st);
232 now = time (NULL);
233 return date>now? 1 : 0;
234 }
235
236
237 /* Dialog box procedure for key generation. */
238 BOOL CALLBACK
239 keygen_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
240 {
241 static genkey_s *ctx;
242 SYSTEMTIME st;
243 gpgme_error_t err;
244 char *utf8_name =NULL, *utf8_comment = NULL;
245 char email[128], t[64];
246 char *pwd;
247 char *expire = NULL, *fpr=NULL;
248 int bits, use_comment, keytype = 0;
249 int cancel = 0;
250 char *p;
251
252 switch (msg) {
253 case WM_INITDIALOG:
254 if (lparam != 0)
255 ctx = (genkey_s *)lparam;
256 SetWindowText (dlg, _("Key Generation"));
257 SetDlgItemText(dlg, IDC_KEYGEN_INFO,
258 _("NOTE: Key generation can be a lengthy process! Please wait until "
259 "you get the message that key generation has finished."));
260 SetDlgItemText (dlg, IDC_KEYGEN_SUBKEYINF, _("Subkey size in &bits:"));
261 SetDlgItemText (dlg, IDC_KEYGEN_NAMEINF, _("&Real name:"));
262 SetDlgItemText (dlg, IDC_KEYGEN_COMMINF, _("&Comment (optional):"));
263 SetDlgItemText (dlg, IDC_KEYGEN_EMAILINF, _("Email &address:"));
264 SetDlgItemText (dlg, IDC_KEYGEN_EXPINF, _("&Expire date:"));
265 SetDlgItemText (dlg, IDC_KEYGEN_KEYTYPEINF, _("Key &type:"));
266 SetDlgItemText (dlg, IDC_KEYGEN_EXPNEVER, _("&Never"));
267 SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
268
269 SetDlgItemInt (dlg, IDC_KEYGEN_SUBKEYBITS, DFAULT_KEYSIZE, FALSE);
270 CheckDlgButton (dlg, IDC_KEYGEN_HIDEPWD, BST_CHECKED);
271 CheckDlgButton (dlg, IDC_KEYGEN_EXPNEVER, BST_CHECKED);
272 EnableWindow (GetDlgItem (dlg, IDC_KEYGEN_EXPDATE), FALSE);
273 fill_keytype_box (dlg);
274 center_window (dlg, NULL);
275 SetForegroundWindow (dlg);
276 return TRUE;
277
278 case WM_DESTROY:
279 balloon_msg_disable ();
280 break;
281
282 case WM_HELP:
283 html_help_show(32);
284 break;
285
286 case WM_COMMAND:
287 if (HIWORD (wparam) == CBN_SELCHANGE &&
288 LOWORD (wparam) == IDC_KEYGEN_KEYTYPE) {
289 keytype = SendMessage ((HWND)lparam, CB_GETCURSEL, 0, 0);
290
291 bits = DFAULT_KEYSIZE;
292 SetDlgItemInt (dlg, IDC_KEYGEN_SUBKEYBITS, bits, FALSE);
293 }
294
295 if (HIWORD (wparam) == BN_CLICKED &&
296 LOWORD (wparam) == IDC_KEYGEN_EXPNEVER) {
297 int never = IsDlgButtonChecked (dlg, IDC_KEYGEN_EXPNEVER);
298 EnableWindow (GetDlgItem (dlg, IDC_KEYGEN_EXPDATE), !never);
299 }
300
301 switch (LOWORD (wparam)) {
302 case IDOK:
303 balloon_msg_disable ();
304 bits = GetDlgItemInt (dlg, IDC_KEYGEN_SUBKEYBITS, NULL, FALSE);
305 if (bits < 2048 || bits > 4096) {
306 show_balloon_msg (GetDlgItem (dlg, IDC_KEYGEN_SUBKEYBITS),
307 _("Invalid keysize value. Allowed values 2048-4096 bits."),
308 IDI_ERROR);
309 return FALSE;
310 }
311 if (bits > DFAULT_KEYSIZE) {
312 int id = msg_box (dlg, _("Do you really need such a large key?"),
313 _("Key Generation"), MB_YESNO);
314 if (id == IDNO)
315 bits = DFAULT_KEYSIZE;
316 }
317 if (!GetDlgItemText_utf8 (dlg, IDC_KEYGEN_NAME, &utf8_name)) {
318 show_balloon_msg (GetDlgItem (dlg, IDC_KEYGEN_NAME),
319 _("Please enter the name."),
320 IDI_ERROR);
321 return FALSE;
322 }
323 if (strchr (utf8_name, '@')) {
324 show_balloon_msg (GetDlgItem (dlg, IDC_KEYGEN_NAME),
325 _("Please do not enter the email address in the name field."),
326 IDI_WARNING);
327 free_if_alloc (utf8_name);
328 return FALSE;
329 }
330 if (!GetDlgItemText (dlg, IDC_KEYGEN_EMAIL, email, DIM (email) -1)
331 || check_email_address (email)) {
332 show_balloon_msg (GetDlgItem (dlg, IDC_KEYGEN_EMAIL),
333 _("Please enter a valid email address."),
334 IDI_ERROR);
335 free_if_alloc (utf8_name);
336 return FALSE;
337 }
338 use_comment = GetDlgItemText_utf8 (dlg, IDC_KEYGEN_COMMENT,
339 &utf8_comment);
340 if (use_comment > 0 && strchr (utf8_comment, '@')) {
341 show_balloon_msg (GetDlgItem (dlg, IDC_KEYGEN_COMMENT),
342 _("Please do NOT enter the email address in the comment field."),
343 IDI_WARNING);
344 free_if_alloc (utf8_name);
345 free_if_alloc (utf8_comment);
346 return TRUE;
347 }
348 keytype = SendDlgItemMessage (dlg, IDC_KEYGEN_KEYTYPE, CB_GETCURSEL, 0, 0) + 1;
349 if (IsDlgButtonChecked (dlg, IDC_KEYGEN_EXPNEVER))
350 expire = NULL;
351 else {
352 DateTime_GetSystemtime (GetDlgItem (dlg, IDC_KEYGEN_EXPDATE), &st);
353 if (!keygen_check_date (&st)) {
354 free_if_alloc (utf8_name);
355 free_if_alloc (utf8_comment);
356 show_balloon_msg (GetDlgItem (dlg, IDC_KEYGEN_EXPDATE),
357 _("The date you have chosen has already passed or is today."),
358 IDI_ERROR);
359 return TRUE;
360 }
361 _snprintf (t, DIM (t)-1, "%04d-%02d-%02d", st.wYear, st.wMonth, st.wDay);
362 expire = t;
363 }
364
365 /* We don't allow empty passphrases during key generation. */
366 pwd = request_passphrase2 (_("Key Generation"),
367 PASSDLG_STRICT|PASSDLG_WARN_UTF8|PASSDLG_NOTEMPTY, &cancel);
368 if (cancel) {
369 sfree_if_alloc (pwd);
370 free_if_alloc (utf8_name);
371 free_if_alloc (utf8_comment);
372 return FALSE;
373 }
374 if (!pwd) {
375 msg_box (dlg, _("Please enter the passphrase."),
376 _("Key Generation"), MB_ERR);
377 free_if_alloc (utf8_name);
378 free_if_alloc (utf8_comment);
379 return FALSE;
380 }
381
382 p = gpg_genkey_params (keytype, bits, utf8_name,
383 !use_comment && !utf8_comment? NULL :utf8_comment,
384 email, expire, pwd);
385 free_if_alloc (utf8_name);
386 free_if_alloc (utf8_comment);
387 keygen_cb_dlg_create ();
388 err = gpg_genkey (p, keygen_cb, &fpr);
389 sfree_if_alloc (pwd);
390 sfree_if_alloc (p); /* burn the passphrase */
391 keygen_cb_dlg_destroy (1);
392 if (err) {
393 free_if_alloc (fpr);
394 msg_box (dlg, gpgme_strerror (err), _("Key Generation"), MB_ERR);
395 return FALSE;
396 }
397 status_box (dlg, _("Key Generation completed"), _("GnuPG Status"));
398
399 keycache_update (0, fpr);
400 keycache_update (1, fpr);
401 free_if_alloc (fpr);
402
403 reset_dlg_fields (dlg);
404 backup_keyrings (dlg);
405 if (ctx)
406 ctx->cancel = 0;
407 EndDialog (dlg, TRUE);
408 return TRUE;
409
410 case IDCANCEL:
411 if (ctx)
412 ctx->cancel = 1;
413 EndDialog (dlg, FALSE);
414 return FALSE;
415 }
416 break;
417 }
418
419 return FALSE;
420 }
421
422
423 /* Wizard like keygen dialog for novice users. */
424 BOOL CALLBACK
425 keygen_wizard_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
426 {
427 static genkey_s *ctx;
428 static int pubkey_algo = GPG_KEYGEN_RSA_RSA;
429 gpgme_error_t err;
430 char email[128];
431 char *utf8_name=NULL, *p, *fpr=NULL;
432 char *pass = NULL;
433 int cancel = 0;
434
435 switch (msg) {
436 case WM_INITDIALOG:
437 ctx = (genkey_s *)lparam;
438 ShowWindow (GetDlgItem (dlg, IDC_KEYWIZARD_USEOTHERPK), SW_HIDE);
439 //SetDlgItemText (dlg, IDC_KEYWIZARD_USEOTHERPK, _("&Prefer DSA/ELG keys"));
440 SetDlgItemText (dlg, IDC_KEYWIZARD_NAMEINF, _("Real name:"));
441 SetDlgItemText (dlg, IDC_KEYWIZARD_EMAILINF, _("Email address:"));
442 SetDlgItemText (dlg, IDC_KEYWIZARD_TITLEINF, _("Name and E-Mail Assignment"));
443 SetDlgItemText (dlg, IDC_KEYWIZARD_TEXT1INF, _("Every key pair must have a name associated with it. The name and\nemail address let your correspondents know that your public key they\nare using belongs to us."));
444 SetDlgItemText (dlg, IDC_KEYWIZARD_TEXT2INF, _("By associating an email address with your key pair, you will enable WinPT to assist your correspondents in selecting the correct public\nkey when communicating with you."));
445 SetWindowText (dlg, _("Key Generation Wizard"));
446 SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
447 SetForegroundWindow (dlg);
448 center_window (dlg, NULL);
449 break;
450
451 case WM_DESTROY:
452 balloon_msg_disable ();
453 break;
454
455 case WM_COMMAND:
456 switch (HIWORD (wparam)) {
457 case BN_CLICKED:
458 if ((int)LOWORD (wparam) == IDC_KEYWIZARD_USEOTHERPK &&
459 IsDlgButtonChecked(dlg, IDC_KEYWIZARD_USEOTHERPK)) {
460 msg_box (dlg, _("Because this limits the key size of the primary key to 1024-bit,\n"
461 "this option is not recommend for long-term security keys."),
462 _("Key Generation"), MB_INFO);
463 }
464
465 break;
466 }
467 switch (LOWORD( wparam)) {
468 case IDOK:
469 balloon_msg_disable ();
470 if (!GetDlgItemText_utf8 (dlg, IDC_KEYWIZARD_NAME, &utf8_name)) {
471 show_balloon_msg (GetDlgItem (dlg, IDC_KEYWIZARD_NAME),
472 _("Please enter the name."), IDI_ERROR);
473 return FALSE;
474 }
475 if (strchr (utf8_name, '@')) {
476 show_balloon_msg (GetDlgItem (dlg, IDC_KEYWIZARD_NAME),
477 _("Please do not enter the email address in the name field."),
478 IDI_WARNING);
479 free_if_alloc (utf8_name);
480 return FALSE;
481 }
482 if (!GetDlgItemText (dlg, IDC_KEYWIZARD_EMAIL, email, DIM (email)-1)
483 || check_email_address (email)) {
484 show_balloon_msg (GetDlgItem (dlg, IDC_KEYWIZARD_EMAIL),
485 _("Please enter a valid email address."),
486 IDI_ERROR);
487 free_if_alloc (utf8_name);
488 return FALSE;
489 }
490 if (strchr (email, '<') || strchr (email, '>')) {
491 show_balloon_msg (GetDlgItem (dlg, IDC_KEYWIZARD_EMAIL),
492 _("Please do not add '<' or '>' to the email address."),
493 IDI_WARNING);
494 free_if_alloc (utf8_name);
495 return FALSE;
496 }
497
498 /* We don't allow empty passphrases during key generation. */
499 pass = request_passphrase2 (_("Key Generation"),
500 PASSDLG_STRICT|PASSDLG_WARN_UTF8|PASSDLG_NOTEMPTY, &cancel);
501 if (cancel) {
502 free_if_alloc (utf8_name);
503 return FALSE;
504 }
505 if (IsDlgButtonChecked (dlg, IDC_KEYWIZARD_USEOTHERPK))
506 pubkey_algo = GPG_KEYGEN_DSA_ELG;
507 p = gpg_genkey_params (pubkey_algo, DFAULT_KEYSIZE, utf8_name,
508 NULL, email, NULL, pass);
509 free_if_alloc (utf8_name);
510 keygen_cb_dlg_create();
511 err = gpg_genkey (p, keygen_cb, &fpr);
512 keygen_cb_dlg_destroy (1);
513 sfree_if_alloc (p);
514 sfree_if_alloc (pass);
515 if (err) {
516 msg_box (dlg, gpgme_strerror (err),
517 _("Key Generation Wizard"), MB_ERR);
518 free_if_alloc (fpr);
519 return FALSE;
520 }
521 status_box (dlg, _("Key Generation completed"), _("GnuPG Status"));
522 keycache_update (0, fpr);
523 keycache_update (1, fpr);
524 free_if_alloc (fpr);
525
526 backup_keyrings (dlg);
527 if (ctx != NULL)
528 ctx->cancel = 0;
529 EndDialog (dlg, TRUE);
530 break;
531
532 case IDCANCEL:
533 if (ctx != NULL)
534 ctx->cancel = 1;
535 EndDialog (dlg, FALSE);
536 break;
537 }
538 break;
539 }
540 return FALSE;
541 }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26