e160f453f70383d0ebaa4444896e74f41a1ac796
[gnupg.git] / agent / genkey.c
1 /* pksign.c - Generate a keypair
2  *      Copyright (C) 2002, 2003, 2004, 2007 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
31 static int
32 store_key (gcry_sexp_t private, const char *passphrase, int force)
33 {
34   int rc;
35   unsigned char *buf;
36   size_t len;
37   unsigned char grip[20];
38   
39   if ( !gcry_pk_get_keygrip (private, grip) )
40     {
41       log_error ("can't calculate keygrip\n");
42       return gpg_error (GPG_ERR_GENERAL);
43     }
44
45   len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, NULL, 0);
46   assert (len);
47   buf = gcry_malloc_secure (len);
48   if (!buf)
49       return out_of_core ();
50   len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
51   assert (len);
52
53   if (passphrase)
54     {
55       unsigned char *p;
56
57       rc = agent_protect (buf, passphrase, &p, &len);
58       if (rc)
59         {
60           xfree (buf);
61           return rc;
62         }
63       xfree (buf);
64       buf = p;
65     }
66
67   rc = agent_write_private_key (grip, buf, len, force);
68   xfree (buf);
69   return rc;
70 }
71
72
73 /* Check whether the passphrase PW is suitable. Returns 0 if the
74    passphrase is suitable and true if it is not and the user should be
75    asked to provide a different one. */
76 int
77 check_passphrase_constraints (ctrl_t ctrl, const char *pw)
78 {
79   gpg_error_t err;
80   unsigned int minlen = opt.min_passphrase_len;
81   
82   if (!pw)
83     pw = "";
84
85   if (utf8_charcount (pw) < minlen ) 
86     {
87       char *desc = xtryasprintf 
88         ( ngettext ("Warning:  You have entered a passphrase that%%0A"
89                     "is obviously not secure.  A passphrase should%%0A"
90                     "be at least %u character long.", 
91                     "Warning:  You have entered a passphrase that%%0A"
92                     "is obviously not secure.  A passphrase should%%0A"
93                     "be at least %u characters long.", minlen), minlen );
94       if (!desc)
95         return gpg_error_from_syserror ();
96       
97       err = agent_get_confirmation (ctrl, desc,
98                                     _("Take this one anyway"),
99                                     _("Enter new passphrase"));
100       xfree (desc);
101       if (err)
102         return err;
103     }
104
105   if (!*pw)
106     {
107       const char *desc = _("You have not entered a passphrase - "
108                            "this is in general a bad idea!%0A"
109                            "Please confirm that you do not want to "
110                            "have any protection on your key.");
111       
112       err = agent_get_confirmation (ctrl, desc,
113                                     _("Yes, protection is not needed"),
114                                     _("Enter new passphrase"));
115       if (err)
116         return err;
117     }
118
119   return 0;
120 }
121
122
123 /* Callback function to compare the first entered PIN with the one
124    currently being entered. */
125 static int
126 reenter_compare_cb (struct pin_entry_info_s *pi)
127 {
128   const char *pin1 = pi->check_cb_arg;
129
130   if (!strcmp (pin1, pi->pin))
131     return 0; /* okay */
132   return -1;
133 }
134
135
136
137 /* Generate a new keypair according to the parameters given in
138    KEYPARAM */
139 int
140 agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen,
141               membuf_t *outbuf) 
142 {
143   gcry_sexp_t s_keyparam, s_key, s_private, s_public;
144   struct pin_entry_info_s *pi, *pi2;
145   int rc;
146   size_t len;
147   char *buf;
148
149   rc = gcry_sexp_sscan (&s_keyparam, NULL, keyparam, keyparamlen);
150   if (rc)
151     {
152       log_error ("failed to convert keyparam: %s\n", gpg_strerror (rc));
153       return gpg_error (GPG_ERR_INV_DATA);
154     }
155
156   /* Get the passphrase now, cause key generation may take a while. */
157   {
158     const char *text1 = _("Please enter the passphrase to%0A"
159                                "to protect your new key");
160     const char *text2 = _("Please re-enter this passphrase");
161     const char *initial_errtext = NULL;
162
163     pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
164     pi2 = pi + (sizeof *pi + 100);
165     pi->max_length = 100;
166     pi->max_tries = 3;
167     pi2->max_length = 100;
168     pi2->max_tries = 3;
169     pi2->check_cb = reenter_compare_cb;
170     pi2->check_cb_arg = pi->pin;
171
172   next_try:
173     rc = agent_askpin (ctrl, text1, NULL, initial_errtext, pi);
174     initial_errtext = NULL;
175     if (!rc)
176       {
177         if (check_passphrase_constraints (ctrl, pi->pin))
178           {
179             pi->failed_tries = 0;
180             pi2->failed_tries = 0;
181             goto next_try;
182           }
183         if (pi->pin && *pi->pin)
184           {
185             rc = agent_askpin (ctrl, text2, NULL, NULL, pi2);
186             if (rc == -1)
187               { /* The re-entered one did not match and the user did not
188                    hit cancel. */
189                 initial_errtext = _("does not match - try again");
190                 goto next_try;
191               }
192           }
193       }
194     if (rc)
195       {
196         xfree (pi);
197         return rc;
198       }
199         
200     if (!*pi->pin)
201       {
202         xfree (pi);
203         pi = NULL; /* User does not want a passphrase. */
204       }
205   }
206
207   rc = gcry_pk_genkey (&s_key, s_keyparam );
208   gcry_sexp_release (s_keyparam);
209   if (rc)
210     {
211       log_error ("key generation failed: %s\n", gpg_strerror (rc));
212       xfree (pi);
213       return rc;
214     }
215
216   /* break out the parts */
217   s_private = gcry_sexp_find_token (s_key, "private-key", 0);
218   if (!s_private)
219     {
220       log_error ("key generation failed: invalid return value\n");
221       gcry_sexp_release (s_key);
222       xfree (pi);
223       return gpg_error (GPG_ERR_INV_DATA);
224     }
225   s_public = gcry_sexp_find_token (s_key, "public-key", 0);
226   if (!s_public)
227     {
228       log_error ("key generation failed: invalid return value\n");
229       gcry_sexp_release (s_private);
230       gcry_sexp_release (s_key);
231       xfree (pi);
232       return gpg_error (GPG_ERR_INV_DATA);
233     }
234   gcry_sexp_release (s_key); s_key = NULL;
235   
236   /* store the secret key */
237   if (DBG_CRYPTO)
238     log_debug ("storing private key\n");
239   rc = store_key (s_private, pi? pi->pin:NULL, 0);
240   xfree (pi); pi = NULL;
241   gcry_sexp_release (s_private);
242   if (rc)
243     {
244       gcry_sexp_release (s_public);
245       return rc;
246     }
247
248   /* return the public key */
249   if (DBG_CRYPTO)
250     log_debug ("returning public key\n");
251   len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, NULL, 0);
252   assert (len);
253   buf = xtrymalloc (len);
254   if (!buf)
255     {
256       gpg_error_t tmperr = out_of_core ();
257       gcry_sexp_release (s_private);
258       gcry_sexp_release (s_public);
259       return tmperr;
260     }
261   len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, buf, len);
262   assert (len);
263   put_membuf (outbuf, buf, len);
264   gcry_sexp_release (s_public);
265   xfree (buf);
266
267   return 0;
268 }
269
270
271 \f
272 /* Apply a new passpahrse to the key S_SKEY and store it. */
273 int
274 agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey) 
275 {
276   struct pin_entry_info_s *pi, *pi2;
277   int rc;
278
279   {
280     const char *text1 = _("Please enter the new passphrase");
281     const char *text2 = _("Please re-enter this passphrase");
282     const char *initial_errtext = NULL;
283
284     pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
285     pi2 = pi + (sizeof *pi + 100);
286     pi->max_length = 100;
287     pi->max_tries = 3;
288     pi2->max_length = 100;
289     pi2->max_tries = 3;
290     pi2->check_cb = reenter_compare_cb;
291     pi2->check_cb_arg = pi->pin;
292
293   next_try:
294     rc = agent_askpin (ctrl, text1, NULL, initial_errtext, pi);
295     initial_errtext = NULL;
296     if (!rc)
297       {
298         if (check_passphrase_constraints (ctrl, pi->pin))
299           {
300             pi->failed_tries = 0;
301             pi2->failed_tries = 0;
302             goto next_try;
303           }
304         /* Unless the passphrase is empty, ask to confirm it.  */
305         if (pi->pin && *pi->pin)
306           {
307             rc = agent_askpin (ctrl, text2, NULL, NULL, pi2);
308             if (rc == -1)
309               { /* The re-entered one did not match and the user did not
310                    hit cancel. */
311                 initial_errtext = _("does not match - try again");
312                 goto next_try;
313               }
314           }
315       }
316     if (rc)
317       {
318         xfree (pi);
319         return rc;
320       }
321
322     if (!*pi->pin)
323       {
324         xfree (pi);
325         pi = NULL; /* User does not want a passphrase. */
326       }
327   }
328
329   rc = store_key (s_skey, pi? pi->pin:NULL, 1);
330   xfree (pi);
331   return 0;
332 }