* query.c (agent_askpin): Hack to show the right default prompt.
[gnupg.git] / agent / genkey.c
1 /* pksign.c - Generate a keypair
2  *      Copyright (C) 2002 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 private, const char *passphrase)
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 seterr (General_Error);
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 seterr (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, 0);
69   xfree (buf);
70   return rc;
71 }
72
73 /* Callback function to compare the first entered PIN with the one
74    currently beeing 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 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", gcry_strerror (rc));
104       return seterr (Invalid_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 (text1, pi);
123     if (!rc)
124       rc = agent_askpin (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", gcry_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 seterr (Invalid_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 seterr (Invalid_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);
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 = xmalloc (len);
179   if (!buf)
180     {
181       gcry_sexp_release (s_private);
182       gcry_sexp_release (s_public);
183       return seterr (Out_Of_Core);
184     }
185   len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, buf, len);
186   assert (len);
187   if (fwrite (buf, len, 1, outfp) != 1)
188     {
189       log_error ("error writing public key: %s\n", strerror (errno));
190       gcry_sexp_release (s_private);
191       gcry_sexp_release (s_public);
192       xfree (buf);
193       return seterr (File_Create_Error);
194     }
195   gcry_sexp_release (s_public);
196   xfree (buf);
197
198   return 0;
199 }
200