Exporting secret keys via gpg-agent is now basically supported.
[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.  If
294    R_CANCEL_ALL is not NULL and the user canceled by directly closing
295    the window true will be stored at this address.  */
296 gpg_error_t
297 agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
298                           char **r_passphrase, int *r_cancel_all)
299 {
300   gpg_error_t err;
301   const char *text1 = prompt;
302   const char *text2 = _("Please re-enter this passphrase");
303   const char *initial_errtext = NULL;
304   struct pin_entry_info_s *pi, *pi2;
305   
306   *r_passphrase = NULL;
307
308   pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
309   pi2 = pi + (sizeof *pi + 100);
310   pi->max_length = 100;
311   pi->max_tries = 3;
312   pi->with_qualitybar = 1;
313   pi2->max_length = 100;
314   pi2->max_tries = 3;
315   pi2->check_cb = reenter_compare_cb;
316   pi2->check_cb_arg = pi->pin;
317
318  next_try:
319   err = agent_askpin (ctrl, text1, NULL, initial_errtext, pi, r_cancel_all);
320   initial_errtext = NULL;
321   if (!err)
322     {
323       if (check_passphrase_constraints (ctrl, pi->pin, 0))
324         {
325           pi->failed_tries = 0;
326           pi2->failed_tries = 0;
327           goto next_try;
328         }
329       /* Unless the passphrase is empty, ask to confirm it.  */
330       if (pi->pin && *pi->pin)
331         {
332           err = agent_askpin (ctrl, text2, NULL, NULL, pi2, NULL);
333           if (err == -1)
334             { /* The re-entered one did not match and the user did not
335                  hit cancel. */
336               initial_errtext = _("does not match - try again");
337               goto next_try;
338             }
339         }
340     }
341   
342   if (!err && *pi->pin)
343     {
344       /* User wants a passphrase. */
345       *r_passphrase = xtrystrdup (pi->pin);
346       if (!*r_passphrase)
347         err = gpg_error_from_syserror ();
348     }
349   xfree (pi);
350   return err;
351 }
352
353
354
355 /* Generate a new keypair according to the parameters given in
356    KEYPARAM.  If CACHE_NONCE is given first try to lookup a passphrase
357    using the cache nonce. */
358 int
359 agent_genkey (ctrl_t ctrl, const char *cache_nonce,
360               const char *keyparam, size_t keyparamlen,
361               membuf_t *outbuf) 
362 {
363   gcry_sexp_t s_keyparam, s_key, s_private, s_public;
364   char *passphrase;
365   int rc;
366   size_t len;
367   char *buf;
368
369   rc = gcry_sexp_sscan (&s_keyparam, NULL, keyparam, keyparamlen);
370   if (rc)
371     {
372       log_error ("failed to convert keyparam: %s\n", gpg_strerror (rc));
373       return gpg_error (GPG_ERR_INV_DATA);
374     }
375
376   /* Get the passphrase now, cause key generation may take a while. */
377   passphrase = cache_nonce? agent_get_cache (cache_nonce, CACHE_MODE_NONCE):NULL;
378   if (passphrase)
379     rc = 0;
380   else
381     rc = agent_ask_new_passphrase (ctrl, 
382                                    _("Please enter the passphrase to%0A"
383                                      "to protect your new key"),
384                                    &passphrase, NULL);
385   if (rc)
386     return rc;
387
388   rc = gcry_pk_genkey (&s_key, s_keyparam );
389   gcry_sexp_release (s_keyparam);
390   if (rc)
391     {
392       log_error ("key generation failed: %s\n", gpg_strerror (rc));
393       xfree (passphrase);
394       return rc;
395     }
396
397   /* break out the parts */
398   s_private = gcry_sexp_find_token (s_key, "private-key", 0);
399   if (!s_private)
400     {
401       log_error ("key generation failed: invalid return value\n");
402       gcry_sexp_release (s_key);
403       xfree (passphrase);
404       return gpg_error (GPG_ERR_INV_DATA);
405     }
406   s_public = gcry_sexp_find_token (s_key, "public-key", 0);
407   if (!s_public)
408     {
409       log_error ("key generation failed: invalid return value\n");
410       gcry_sexp_release (s_private);
411       gcry_sexp_release (s_key);
412       xfree (passphrase);
413       return gpg_error (GPG_ERR_INV_DATA);
414     }
415   gcry_sexp_release (s_key); s_key = NULL;
416   
417   /* store the secret key */
418   if (DBG_CRYPTO)
419     log_debug ("storing private key\n");
420   rc = store_key (s_private, passphrase, 0);
421   if (!rc)
422     {
423       if (!cache_nonce)
424         {
425           char tmpbuf[12];
426           gcry_create_nonce (tmpbuf, 12);
427           cache_nonce = bin2hex (tmpbuf, 12, NULL);
428         }
429       if (cache_nonce 
430           && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
431                                passphrase, 900 /*seconds*/))
432         agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL);
433     }
434   xfree (passphrase);
435   passphrase = NULL;
436   gcry_sexp_release (s_private);
437   if (rc)
438     {
439       gcry_sexp_release (s_public);
440       return rc;
441     }
442
443   /* return the public key */
444   if (DBG_CRYPTO)
445     log_debug ("returning public key\n");
446   len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, NULL, 0);
447   assert (len);
448   buf = xtrymalloc (len);
449   if (!buf)
450     {
451       gpg_error_t tmperr = out_of_core ();
452       gcry_sexp_release (s_private);
453       gcry_sexp_release (s_public);
454       return tmperr;
455     }
456   len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, buf, len);
457   assert (len);
458   put_membuf (outbuf, buf, len);
459   gcry_sexp_release (s_public);
460   xfree (buf);
461
462   return 0;
463 }
464
465
466 \f
467 /* Apply a new passphrase to the key S_SKEY and store it. */
468 int
469 agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey) 
470 {
471   int rc;
472   char *passphrase;
473
474   rc = agent_ask_new_passphrase (ctrl, 
475                                  _("Please enter the new passphrase"),
476                                  &passphrase, NULL);
477   if (!rc)
478     {
479       rc = store_key (s_skey, passphrase, 1);
480       xfree (passphrase);
481     }
482   return rc;
483 }