1 /* genkey.c - Generate a keypair
2 * Copyright (C) 2002, 2003, 2004, 2007 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG 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 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG 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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
34 store_key (gcry_sexp_t
private, const char *passphrase
, int force
)
39 unsigned char grip
[20];
41 if ( !gcry_pk_get_keygrip (private, grip
) )
43 log_error ("can't calculate keygrip\n");
44 return gpg_error (GPG_ERR_GENERAL
);
47 len
= gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON
, NULL
, 0);
49 buf
= gcry_malloc_secure (len
);
51 return out_of_core ();
52 len
= gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON
, buf
, len
);
59 rc
= agent_protect (buf
, passphrase
, &p
, &len
);
69 rc
= agent_write_private_key (grip
, buf
, len
, force
);
75 /* Count the number of non-alpha characters in S. Control characters
76 and non-ascii characters are not considered. */
78 nonalpha_count (const char *s
)
83 if (isascii (*s
) && ( isdigit (*s
) || ispunct (*s
) ))
90 /* Check PW against a list of pattern. Return 0 if PW does not match
93 check_passphrase_pattern (ctrl_t ctrl
, const char *pw
)
96 const char *pgmname
= gnupg_module_name (GNUPG_MODULE_NAME_CHECK_PATTERN
);
104 infp
= gnupg_tmpfile ();
107 err
= gpg_error_from_syserror ();
108 log_error (_("error creating temporary file: %s\n"), strerror (errno
));
109 return 1; /* Error - assume password should not be used. */
112 if (fwrite (pw
, strlen (pw
), 1, infp
) != 1)
114 err
= gpg_error_from_syserror ();
115 log_error (_("error writing to temporary file: %s\n"),
118 return 1; /* Error - assume password should not be used. */
123 argv
[i
++] = "--null";
125 argv
[i
++] = opt
.check_passphrase_pattern
,
127 assert (i
< sizeof argv
);
129 if (gnupg_spawn_process_fd (pgmname
, argv
, fileno (infp
), -1, -1, &pid
))
130 result
= 1; /* Execute error - assume password should no be used. */
131 else if (gnupg_wait_process (pgmname
, pid
, NULL
))
132 result
= 1; /* Helper returned an error - probably a match. */
134 result
= 0; /* Success; i.e. no match. */
136 /* Overwrite our temporary file. */
138 for (i
=((strlen (pw
)+99)/100)*100; i
> 0; i
--)
147 take_this_one_anyway2 (ctrl_t ctrl
, const char *desc
, const char *anyway_btn
)
151 if (opt
.enforce_passphrase_constraints
)
153 err
= agent_show_message (ctrl
, desc
, _("Enter new passphrase"));
155 err
= gpg_error (GPG_ERR_CANCELED
);
158 err
= agent_get_confirmation (ctrl
, desc
,
159 anyway_btn
, _("Enter new passphrase"));
165 take_this_one_anyway (ctrl_t ctrl
, const char *desc
)
167 return take_this_one_anyway2 (ctrl
, desc
, _("Take this one anyway"));
171 /* Check whether the passphrase PW is suitable. Returns 0 if the
172 passphrase is suitable and true if it is not and the user should be
173 asked to provide a different one. If SILENT is set, no message are
176 check_passphrase_constraints (ctrl_t ctrl
, const char *pw
, int silent
)
179 unsigned int minlen
= opt
.min_passphrase_len
;
180 unsigned int minnonalpha
= opt
.min_passphrase_nonalpha
;
185 if (utf8_charcount (pw
) < minlen
)
190 return gpg_error (GPG_ERR_INV_PASSPHRASE
);
193 ( ngettext ("Warning: You have entered an insecure passphrase.%%0A"
194 "A passphrase should be at least %u character long.",
195 "Warning: You have entered an insecure passphrase.%%0A"
196 "A passphrase should be at least %u characters long.",
199 return gpg_error_from_syserror ();
200 err
= take_this_one_anyway (ctrl
, desc
);
206 if (nonalpha_count (pw
) < minnonalpha
)
211 return gpg_error (GPG_ERR_INV_PASSPHRASE
);
214 ( ngettext ("Warning: You have entered an insecure passphrase.%%0A"
215 "A passphrase should contain at least %u digit or%%0A"
216 "special character.",
217 "Warning: You have entered an insecure passphrase.%%0A"
218 "A passphrase should contain at least %u digits or%%0A"
219 "special characters.",
220 minnonalpha
), minnonalpha
);
222 return gpg_error_from_syserror ();
223 err
= take_this_one_anyway (ctrl
, desc
);
229 /* If configured check the passphrase against a list of know words
230 and pattern. The actual test is done by an external program.
231 The warning message is generic to give the user no hint on how to
232 circumvent this list. */
233 if (*pw
&& opt
.check_passphrase_pattern
&&
234 check_passphrase_pattern (ctrl
, pw
))
237 /* */ _("Warning: You have entered an insecure passphrase.%%0A"
238 "A passphrase may not be a known term or match%%0A"
242 return gpg_error (GPG_ERR_INV_PASSPHRASE
);
244 err
= take_this_one_anyway (ctrl
, desc
);
249 /* The final check is to warn about an empty passphrase. */
252 const char *desc
= (opt
.enforce_passphrase_constraints
?
253 _("You have not entered a passphrase!%0A"
254 "An empty passphrase is not allowed.") :
255 _("You have not entered a passphrase - "
256 "this is in general a bad idea!%0A"
257 "Please confirm that you do not want to "
258 "have any protection on your key."));
261 return gpg_error (GPG_ERR_INV_PASSPHRASE
);
263 err
= take_this_one_anyway2 (ctrl
, desc
,
264 _("Yes, protection is not needed"));
273 /* Callback function to compare the first entered PIN with the one
274 currently being entered. */
276 reenter_compare_cb (struct pin_entry_info_s
*pi
)
278 const char *pin1
= pi
->check_cb_arg
;
280 if (!strcmp (pin1
, pi
->pin
))
287 /* Generate a new keypair according to the parameters given in
290 agent_genkey (ctrl_t ctrl
, const char *keyparam
, size_t keyparamlen
,
293 gcry_sexp_t s_keyparam
, s_key
, s_private
, s_public
;
294 struct pin_entry_info_s
*pi
, *pi2
;
299 rc
= gcry_sexp_sscan (&s_keyparam
, NULL
, keyparam
, keyparamlen
);
302 log_error ("failed to convert keyparam: %s\n", gpg_strerror (rc
));
303 return gpg_error (GPG_ERR_INV_DATA
);
306 /* Get the passphrase now, cause key generation may take a while. */
308 const char *text1
= _("Please enter the passphrase to%0A"
309 "to protect your new key");
310 const char *text2
= _("Please re-enter this passphrase");
311 const char *initial_errtext
= NULL
;
313 pi
= gcry_calloc_secure (2, sizeof (*pi
) + 100);
314 pi2
= pi
+ (sizeof *pi
+ 100);
315 pi
->max_length
= 100;
317 pi
->with_qualitybar
= 1;
318 pi2
->max_length
= 100;
320 pi2
->check_cb
= reenter_compare_cb
;
321 pi2
->check_cb_arg
= pi
->pin
;
324 rc
= agent_askpin (ctrl
, text1
, NULL
, initial_errtext
, pi
);
325 initial_errtext
= NULL
;
328 if (check_passphrase_constraints (ctrl
, pi
->pin
, 0))
330 pi
->failed_tries
= 0;
331 pi2
->failed_tries
= 0;
334 if (pi
->pin
&& *pi
->pin
)
336 rc
= agent_askpin (ctrl
, text2
, NULL
, NULL
, pi2
);
338 { /* The re-entered one did not match and the user did not
340 initial_errtext
= _("does not match - try again");
354 pi
= NULL
; /* User does not want a passphrase. */
358 rc
= gcry_pk_genkey (&s_key
, s_keyparam
);
359 gcry_sexp_release (s_keyparam
);
362 log_error ("key generation failed: %s\n", gpg_strerror (rc
));
367 /* break out the parts */
368 s_private
= gcry_sexp_find_token (s_key
, "private-key", 0);
371 log_error ("key generation failed: invalid return value\n");
372 gcry_sexp_release (s_key
);
374 return gpg_error (GPG_ERR_INV_DATA
);
376 s_public
= gcry_sexp_find_token (s_key
, "public-key", 0);
379 log_error ("key generation failed: invalid return value\n");
380 gcry_sexp_release (s_private
);
381 gcry_sexp_release (s_key
);
383 return gpg_error (GPG_ERR_INV_DATA
);
385 gcry_sexp_release (s_key
); s_key
= NULL
;
387 /* store the secret key */
389 log_debug ("storing private key\n");
390 rc
= store_key (s_private
, pi
? pi
->pin
:NULL
, 0);
391 xfree (pi
); pi
= NULL
;
392 gcry_sexp_release (s_private
);
395 gcry_sexp_release (s_public
);
399 /* return the public key */
401 log_debug ("returning public key\n");
402 len
= gcry_sexp_sprint (s_public
, GCRYSEXP_FMT_CANON
, NULL
, 0);
404 buf
= xtrymalloc (len
);
407 gpg_error_t tmperr
= out_of_core ();
408 gcry_sexp_release (s_private
);
409 gcry_sexp_release (s_public
);
412 len
= gcry_sexp_sprint (s_public
, GCRYSEXP_FMT_CANON
, buf
, len
);
414 put_membuf (outbuf
, buf
, len
);
415 gcry_sexp_release (s_public
);
423 /* Apply a new passpahrse to the key S_SKEY and store it. */
425 agent_protect_and_store (ctrl_t ctrl
, gcry_sexp_t s_skey
)
427 struct pin_entry_info_s
*pi
, *pi2
;
431 const char *text1
= _("Please enter the new passphrase");
432 const char *text2
= _("Please re-enter this passphrase");
433 const char *initial_errtext
= NULL
;
435 pi
= gcry_calloc_secure (2, sizeof (*pi
) + 100);
436 pi2
= pi
+ (sizeof *pi
+ 100);
437 pi
->max_length
= 100;
439 pi
->with_qualitybar
= 1;
440 pi2
->max_length
= 100;
442 pi2
->check_cb
= reenter_compare_cb
;
443 pi2
->check_cb_arg
= pi
->pin
;
446 rc
= agent_askpin (ctrl
, text1
, NULL
, initial_errtext
, pi
);
447 initial_errtext
= NULL
;
450 if (check_passphrase_constraints (ctrl
, pi
->pin
, 0))
452 pi
->failed_tries
= 0;
453 pi2
->failed_tries
= 0;
456 /* Unless the passphrase is empty, ask to confirm it. */
457 if (pi
->pin
&& *pi
->pin
)
459 rc
= agent_askpin (ctrl
, text2
, NULL
, NULL
, pi2
);
461 { /* The re-entered one did not match and the user did not
463 initial_errtext
= _("does not match - try again");
477 pi
= NULL
; /* User does not want a passphrase. */
481 rc
= store_key (s_skey
, pi
? pi
->pin
:NULL
, 1);