* call-agent.c (agent_scd_getattr): Don't clear the passed info
[gnupg.git] / agent / genkey.c
1 /* pksign.c - Generate a keypair
2  *      Copyright (C) 2002, 2003 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 2 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
28
29 #include "agent.h"
30 #include "i18n.h"
31
32 static int
33 store_key (gcry_sexp_t private, const char *passphrase, int force)
34 {
35   int rc;
36   char *buf;
37   size_t len;
38   unsigned char grip[20];
39   
40   if ( !gcry_pk_get_keygrip (private, grip) )
41     {
42       log_error ("can't calculate keygrip\n");
43       return gpg_error (GPG_ERR_GENERAL);
44     }
45
46   len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, NULL, 0);
47   assert (len);
48   buf = gcry_malloc_secure (len);
49   if (!buf)
50       return out_of_core ();
51   len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
52   assert (len);
53
54   if (passphrase)
55     {
56       unsigned char *p;
57
58       rc = agent_protect (buf, passphrase, &p, &len);
59       if (rc)
60         {
61           xfree (buf);
62           return rc;
63         }
64       xfree (buf);
65       buf = p;
66     }
67
68   rc = agent_write_private_key (grip, buf, len, force);
69   xfree (buf);
70   return rc;
71 }
72
73 /* Callback function to compare the first entered PIN with the one
74    currently being entered. */
75 static int
76 reenter_compare_cb (struct pin_entry_info_s *pi)
77 {
78   const char *pin1 = pi->check_cb_arg;
79
80   if (!strcmp (pin1, pi->pin))
81     return 0; /* okay */
82   pi->cb_errtext = _("does not match - try again");
83   return -1;
84 }
85
86
87
88 /* Generate a new keypair according to the parameters given in
89    KEYPARAM */
90 int
91 agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen,
92               FILE *outfp) 
93 {
94   gcry_sexp_t s_keyparam, s_key, s_private, s_public;
95   struct pin_entry_info_s *pi, *pi2;
96   int rc;
97   size_t len;
98   char *buf;
99
100   rc = gcry_sexp_sscan (&s_keyparam, NULL, keyparam, keyparamlen);
101   if (rc)
102     {
103       log_error ("failed to convert keyparam: %s\n", gpg_strerror (rc));
104       return gpg_error (GPG_ERR_INV_DATA);
105     }
106
107   /* Get the passphrase now, cause key generation may take a while. */
108   {
109     const char *text1 = _("Please enter the passphrase to%0A"
110                                "to protect your new key");
111     const char *text2 = _("Please re-enter this passphrase");
112
113     pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
114     pi2 = pi + (sizeof *pi + 100);
115     pi->max_length = 100;
116     pi->max_tries = 3;
117     pi2->max_length = 100;
118     pi2->max_tries = 3;
119     pi2->check_cb = reenter_compare_cb;
120     pi2->check_cb_arg = pi->pin;
121
122     rc = agent_askpin (ctrl, text1, pi);
123     if (!rc)
124       rc = agent_askpin (ctrl, text2, pi2);
125     if (rc)
126       return rc;
127     if (!*pi->pin)
128       {
129         xfree (pi);
130         pi = NULL; /* User does not want a passphrase. */
131       }
132   }
133
134   rc = gcry_pk_genkey (&s_key, s_keyparam );
135   gcry_sexp_release (s_keyparam);
136   if (rc)
137     {
138       log_error ("key generation failed: %s\n", gpg_strerror (rc));
139       xfree (pi);
140       return map_gcry_err (rc);
141     }
142
143   /* break out the parts */
144   s_private = gcry_sexp_find_token (s_key, "private-key", 0);
145   if (!s_private)
146     {
147       log_error ("key generation failed: invalid return value\n");
148       gcry_sexp_release (s_key);
149       xfree (pi);
150       return gpg_error (GPG_ERR_INV_DATA);
151     }
152   s_public = gcry_sexp_find_token (s_key, "public-key", 0);
153   if (!s_public)
154     {
155       log_error ("key generation failed: invalid return value\n");
156       gcry_sexp_release (s_private);
157       gcry_sexp_release (s_key);
158       xfree (pi);
159       return gpg_error (GPG_ERR_INV_DATA);
160     }
161   gcry_sexp_release (s_key); s_key = NULL;
162   
163   /* store the secret key */
164   log_debug ("storing private key\n");
165   rc = store_key (s_private, pi? pi->pin:NULL, 0);
166   xfree (pi); pi = NULL;
167   gcry_sexp_release (s_private);
168   if (rc)
169     {
170       gcry_sexp_release (s_public);
171       return rc;
172     }
173
174   /* return the public key */
175   log_debug ("returning public key\n");
176   len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, NULL, 0);
177   assert (len);
178   buf = xtrymalloc (len);
179   if (!buf)
180     {
181       gpg_error_t tmperr = out_of_core ();
182       gcry_sexp_release (s_private);
183       gcry_sexp_release (s_public);
184       return tmperr;
185     }
186   len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, buf, len);
187   assert (len);
188   if (fwrite (buf, len, 1, outfp) != 1)
189     {
190       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
191       log_error ("error writing public key: %s\n", strerror (errno));
192       gcry_sexp_release (s_private);
193       gcry_sexp_release (s_public);
194       xfree (buf);
195       return tmperr;
196     }
197   gcry_sexp_release (s_public);
198   xfree (buf);
199
200   return 0;
201 }
202
203
204 \f
205 /* Apply a new passpahrse to the key S_SKEY and store it. */
206 int
207 agent_protect_and_store (CTRL ctrl, gcry_sexp_t s_skey) 
208 {
209   struct pin_entry_info_s *pi, *pi2;
210   int rc;
211
212   {
213     const char *text1 = _("Please enter the new passphrase");
214     const char *text2 = _("Please re-enter this passphrase");
215
216     pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
217     pi2 = pi + (sizeof *pi + 100);
218     pi->max_length = 100;
219     pi->max_tries = 3;
220     pi2->max_length = 100;
221     pi2->max_tries = 3;
222     pi2->check_cb = reenter_compare_cb;
223     pi2->check_cb_arg = pi->pin;
224
225     rc = agent_askpin (ctrl, text1, pi);
226     if (!rc)
227       rc = agent_askpin (ctrl, text2, pi2);
228     if (rc)
229       return rc;
230     if (!*pi->pin)
231       {
232         xfree (pi);
233         pi = NULL; /* User does not want a passphrase. */
234       }
235   }
236
237   rc = store_key (s_skey, pi? pi->pin:NULL, 1);
238   xfree (pi);
239   return 0;
240 }