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

Contents of /trunk/Src/wptKeygenDlg.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 314 - (show annotations)
Sun May 13 09:44:03 2007 UTC (17 years, 9 months ago) by twoaday
File size: 16525 byte(s)


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26