More agent support for gpg.
[gnupg.git] / agent / genkey.c
1 /* genkey.c - Generate a keypair
2  * Copyright (C) 2002, 2003, 2004, 2007, 2010 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include <config.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <assert.h>
27
28 #include "agent.h"
29 #include "i18n.h"
30 #include "exechelp.h"
31 #include "sysutils.h"
32
33 static int
34 store_key (gcry_sexp_t private, const char *passphrase, int force)
35 {
36   int rc;
37   unsigned char *buf;
38   size_t len;
39   unsigned char grip[20];
40   
41   if ( !gcry_pk_get_keygrip (private, grip) )
42     {
43       log_error ("can't calculate keygrip\n");
44       return gpg_error (GPG_ERR_GENERAL);
45     }
46
47   len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, NULL, 0);
48   assert (len);
49   buf = gcry_malloc_secure (len);
50   if (!buf)
51       return out_of_core ();
52   len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
53   assert (len);
54
55   if (passphrase)
56     {
57       unsigned char *p;
58
59       rc = agent_protect (buf, passphrase, &p, &len);
60       if (rc)
61         {
62           xfree (buf);
63           return rc;
64         }
65       xfree (buf);
66       buf = p;
67     }
68
69   rc = agent_write_private_key (grip, buf, len, force);
70   xfree (buf);
71   return rc;
72 }
73
74
75 /* Count the number of non-alpha characters in S.  Control characters
76    and non-ascii characters are not considered.  */
77 static size_t
78 nonalpha_count (const char *s)
79 {
80   size_t n;
81
82   for (n=0; *s; s++)
83     if (isascii (*s) && ( isdigit (*s) || ispunct (*s) ))
84       n++;
85
86   return n;
87 }
88
89
90 /* Check PW against a list of pattern.  Return 0 if PW does not match
91    these pattern.  */
92 static int
93 check_passphrase_pattern (ctrl_t ctrl, const char *pw)
94 {
95   gpg_error_t err = 0;
96   const char *pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CHECK_PATTERN);
97   FILE *infp;
98   const char *argv[10];
99   pid_t pid;
100   int result, i;
101
102   (void)ctrl;
103
104   infp = gnupg_tmpfile ();
105   if (!infp)
106     {
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.  */
110     }
111
112   if (fwrite (pw, strlen (pw), 1, infp) != 1)
113     {
114       err = gpg_error_from_syserror ();
115       log_error (_("error writing to temporary file: %s\n"),
116                  strerror (errno));
117       fclose (infp);
118       return 1; /* Error - assume password should not be used.  */
119     }
120   fseek (infp, 0, SEEK_SET);
121   clearerr (infp);
122
123   i = 0;
124   argv[i++] = "--null";
125   argv[i++] = "--",
126   argv[i++] = opt.check_passphrase_pattern,
127   argv[i] = NULL;
128   assert (i < sizeof argv);
129
130   if (gnupg_spawn_process_fd (pgmname, argv, fileno (infp), -1, -1, &pid))
131     result = 1; /* Execute error - assume password should no be used.  */
132   else if (gnupg_wait_process (pgmname, pid, 1, NULL))
133     result = 1; /* Helper returned an error - probably a match.  */
134   else
135     result = 0; /* Success; i.e. no match.  */
136   gnupg_release_process (pid);
137
138   /* Overwrite our temporary file. */
139   fseek (infp, 0, SEEK_SET);
140   clearerr (infp);
141   for (i=((strlen (pw)+99)/100)*100; i > 0; i--)
142     putc ('\xff', infp);
143   fflush (infp);
144   fclose (infp);
145   return result;
146 }
147
148
149 static int 
150 take_this_one_anyway2 (ctrl_t ctrl, const char *desc, const char *anyway_btn)
151 {
152   gpg_error_t err;
153
154   if (opt.enforce_passphrase_constraints)
155     {
156       err = agent_show_message (ctrl, desc, _("Enter new passphrase"));
157       if (!err)
158         err = gpg_error (GPG_ERR_CANCELED);
159     }
160   else
161     err = agent_get_confirmation (ctrl, desc,
162                                   anyway_btn, _("Enter new passphrase"), 0);
163   return err;
164 }
165
166
167 static int 
168 take_this_one_anyway (ctrl_t ctrl, const char *desc)
169 {
170   return take_this_one_anyway2 (ctrl, desc, _("Take this one anyway"));
171 }
172
173
174 /* Check whether the passphrase PW is suitable. Returns 0 if the
175    passphrase is suitable and true if it is not and the user should be
176    asked to provide a different one.  If SILENT is set, no message are
177    displayed.  */
178 int
179 check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent)
180 {
181   gpg_error_t err;
182   unsigned int minlen = opt.min_passphrase_len;
183   unsigned int minnonalpha = opt.min_passphrase_nonalpha;
184
185   if (!pw)
186     pw = "";
187
188   if (utf8_charcount (pw) < minlen ) 
189     {
190       char *desc;
191       
192       if (silent)
193         return gpg_error (GPG_ERR_INV_PASSPHRASE);
194
195       desc = xtryasprintf 
196         ( ngettext ("Warning: You have entered an insecure passphrase.%%0A"
197                     "A passphrase should be at least %u character long.", 
198                     "Warning: You have entered an insecure passphrase.%%0A"
199                     "A passphrase should be at least %u characters long.", 
200                     minlen), minlen );
201       if (!desc)
202         return gpg_error_from_syserror ();
203       err = take_this_one_anyway (ctrl, desc);
204       xfree (desc);
205       if (err)
206         return err;
207     }
208
209   if (nonalpha_count (pw) < minnonalpha ) 
210     {
211       char *desc;
212
213       if (silent)
214         return gpg_error (GPG_ERR_INV_PASSPHRASE);
215
216       desc = xtryasprintf 
217         ( ngettext ("Warning: You have entered an insecure passphrase.%%0A"
218                     "A passphrase should contain at least %u digit or%%0A"
219                     "special character.", 
220                     "Warning: You have entered an insecure passphrase.%%0A"
221                     "A passphrase should contain at least %u digits or%%0A"
222                     "special characters.",
223                     minnonalpha), minnonalpha );
224       if (!desc)
225         return gpg_error_from_syserror ();
226       err = take_this_one_anyway (ctrl, desc);
227       xfree (desc);
228       if (err)
229         return err;
230     }
231
232   /* If configured check the passphrase against a list of know words
233      and pattern.  The actual test is done by an external program.
234      The warning message is generic to give the user no hint on how to
235      circumvent this list.  */
236   if (*pw && opt.check_passphrase_pattern &&
237       check_passphrase_pattern (ctrl, pw))
238     {
239       const char *desc =
240         /* */     _("Warning: You have entered an insecure passphrase.%%0A"
241                     "A passphrase may not be a known term or match%%0A"
242                     "certain pattern.");
243
244       if (silent)
245         return gpg_error (GPG_ERR_INV_PASSPHRASE);
246
247       err = take_this_one_anyway (ctrl, desc);
248       if (err)
249         return err;
250     }
251
252   /* The final check is to warn about an empty passphrase. */
253   if (!*pw)
254     {
255       const char *desc = (opt.enforce_passphrase_constraints?
256                           _("You have not entered a passphrase!%0A"
257                             "An empty passphrase is not allowed.") :
258                           _("You have not entered a passphrase - "
259                             "this is in general a bad idea!%0A"
260                             "Please confirm that you do not want to "
261                             "have any protection on your key."));
262       
263       if (silent)
264         return gpg_error (GPG_ERR_INV_PASSPHRASE);
265
266       err = take_this_one_anyway2 (ctrl, desc,
267                                    _("Yes, protection is not needed"));
268       if (err)
269         return err;
270     }
271
272   return 0;
273 }
274
275
276 /* Callback function to compare the first entered PIN with the one
277    currently being entered. */
278 static int
279 reenter_compare_cb (struct pin_entry_info_s *pi)
280 {
281   const char *pin1 = pi->check_cb_arg;
282
283   if (!strcmp (pin1, pi->pin))
284     return 0; /* okay */
285   return -1;
286 }
287
288
289 /* Ask the user for a new passphrase using PROMPT.  On success the
290    function returns 0 and store the passphrase at R_PASSPHRASE; if the
291    user opted not to use a passphrase NULL will be stored there.  The
292    user needs to free the returned string.  In case of an error and
293    error code is returned and NULL stored at R_PASSPHRASE.  */
294 gpg_error_t
295 agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
296                           char **r_passphrase)
297 {
298   gpg_error_t err;
299   const char *text1 = prompt;
300   const char *text2 = _("Please re-enter this passphrase");
301   const char *initial_errtext = NULL;
302   struct pin_entry_info_s *pi, *pi2;
303   
304   *r_passphrase = NULL;
305
306   pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
307   pi2 = pi + (sizeof *pi + 100);
308   pi->max_length = 100;
309   pi->max_tries = 3;
310   pi->with_qualitybar = 1;
311   pi2->max_length = 100;
312   pi2->max_tries = 3;
313   pi2->check_cb = reenter_compare_cb;
314   pi2->check_cb_arg = pi->pin;
315
316  next_try:
317   err = agent_askpin (ctrl, text1, NULL, initial_errtext, pi);
318   initial_errtext = NULL;
319   if (!err)
320     {
321       if (check_passphrase_constraints (ctrl, pi->pin, 0))
322         {
323           pi->failed_tries = 0;
324           pi2->failed_tries = 0;
325           goto next_try;
326         }
327       /* Unless the passphrase is empty, ask to confirm it.  */
328       if (pi->pin && *pi->pin)
329         {
330           err = agent_askpin (ctrl, text2, NULL, NULL, pi2);
331           if (err == -1)
332             { /* The re-entered one did not match and the user did not
333                  hit cancel. */
334               initial_errtext = _("does not match - try again");
335               goto next_try;
336             }
337         }
338     }
339   
340   if (!err && *pi->pin)
341     {
342       /* User wants a passphrase. */
343       *r_passphrase = xtrystrdup (pi->pin);
344       if (!*r_passphrase)
345         err = gpg_error_from_syserror ();
346     }
347   xfree (pi);
348   return err;
349 }
350
351
352
353 /* Generate a new keypair according to the parameters given in
354    KEYPARAM.  If CACHE_NONCE is given first try to lookup a passphrase
355    using the cache nonce. */
356 int
357 agent_genkey (ctrl_t ctrl, const char *cache_nonce,
358               const char *keyparam, size_t keyparamlen,
359               membuf_t *outbuf) 
360 {
361   gcry_sexp_t s_keyparam, s_key, s_private, s_public;
362   char *passphrase;
363   int rc;
364   size_t len;
365   char *buf;
366
367   rc = gcry_sexp_sscan (&s_keyparam, NULL, keyparam, keyparamlen);
368   if (rc)
369     {
370       log_error ("failed to convert keyparam: %s\n", gpg_strerror (rc));
371       return gpg_error (GPG_ERR_INV_DATA);
372     }
373
374   /* Get the passphrase now, cause key generation may take a while. */
375   passphrase = cache_nonce? agent_get_cache (cache_nonce, CACHE_MODE_NONCE):NULL;
376   if (passphrase)
377     rc = 0;
378   else
379     rc = agent_ask_new_passphrase (ctrl, 
380                                    _("Please enter the passphrase to%0A"
381                                      "to protect your new key"),
382                                    &passphrase);
383   if (rc)
384     return rc;
385
386   rc = gcry_pk_genkey (&s_key, s_keyparam );
387   gcry_sexp_release (s_keyparam);
388   if (rc)
389     {
390       log_error ("key generation failed: %s\n", gpg_strerror (rc));
391       xfree (passphrase);
392       return rc;
393     }
394
395   /* break out the parts */
396   s_private = gcry_sexp_find_token (s_key, "private-key", 0);
397   if (!s_private)
398     {
399       log_error ("key generation failed: invalid return value\n");
400       gcry_sexp_release (s_key);
401       xfree (passphrase);
402       return gpg_error (GPG_ERR_INV_DATA);
403     }
404   s_public = gcry_sexp_find_token (s_key, "public-key", 0);
405   if (!s_public)
406     {
407       log_error ("key generation failed: invalid return value\n");
408       gcry_sexp_release (s_private);
409       gcry_sexp_release (s_key);
410       xfree (passphrase);
411       return gpg_error (GPG_ERR_INV_DATA);
412     }
413   gcry_sexp_release (s_key); s_key = NULL;
414   
415   /* store the secret key */
416   if (DBG_CRYPTO)
417     log_debug ("storing private key\n");
418   rc = store_key (s_private, passphrase, 0);
419   if (!rc)
420     {
421       if (!cache_nonce)
422         {
423           char tmpbuf[12];
424           gcry_create_nonce (tmpbuf, 12);
425           cache_nonce = bin2hex (tmpbuf, 12, NULL);
426         }
427       if (cache_nonce 
428           && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
429                                passphrase, 900 /*seconds*/))
430         agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL);
431     }
432   xfree (passphrase);
433   passphrase = NULL;
434   gcry_sexp_release (s_private);
435   if (rc)
436     {
437       gcry_sexp_release (s_public);
438       return rc;
439     }
440
441   /* return the public key */
442   if (DBG_CRYPTO)
443     log_debug ("returning public key\n");
444   len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, NULL, 0);
445   assert (len);
446   buf = xtrymalloc (len);
447   if (!buf)
448     {
449       gpg_error_t tmperr = out_of_core ();
450       gcry_sexp_release (s_private);
451       gcry_sexp_release (s_public);
452       return tmperr;
453     }
454   len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, buf, len);
455   assert (len);
456   put_membuf (outbuf, buf, len);
457   gcry_sexp_release (s_public);
458   xfree (buf);
459
460   return 0;
461 }
462
463
464 \f
465 /* Apply a new passphrase to the key S_SKEY and store it. */
466 int
467 agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey) 
468 {
469   int rc;
470   char *passphrase;
471
472   rc = agent_ask_new_passphrase (ctrl, 
473                                  _("Please enter the new passphrase"),
474                                  &passphrase);
475   if (!rc)
476     {
477       rc = store_key (s_skey, passphrase, 1);
478       xfree (passphrase);
479     }
480   return rc;
481 }