2006-10-24 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / agent / genkey.c
bloba1f9f38f4664403ee6cb141b3516bf936b722bfd
1 /* pksign.c - Generate a keypair
2 * Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19 * USA.
22 #include <config.h>
23 #include <errno.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <assert.h>
30 #include "agent.h"
31 #include "i18n.h"
33 static int
34 store_key (gcry_sexp_t private, const char *passphrase, int force)
36 int rc;
37 unsigned char *buf;
38 size_t len;
39 unsigned char grip[20];
41 if ( !gcry_pk_get_keygrip (private, grip) )
43 log_error ("can't calculate keygrip\n");
44 return gpg_error (GPG_ERR_GENERAL);
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);
55 if (passphrase)
57 unsigned char *p;
59 rc = agent_protect (buf, passphrase, &p, &len);
60 if (rc)
62 xfree (buf);
63 return rc;
65 xfree (buf);
66 buf = p;
69 rc = agent_write_private_key (grip, buf, len, force);
70 xfree (buf);
71 return rc;
74 /* Callback function to compare the first entered PIN with the one
75 currently being entered. */
76 static int
77 reenter_compare_cb (struct pin_entry_info_s *pi)
79 const char *pin1 = pi->check_cb_arg;
81 if (!strcmp (pin1, pi->pin))
82 return 0; /* okay */
83 return -1;
88 /* Generate a new keypair according to the parameters given in
89 KEYPARAM */
90 int
91 agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen,
92 membuf_t *outbuf)
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;
100 rc = gcry_sexp_sscan (&s_keyparam, NULL, keyparam, keyparamlen);
101 if (rc)
103 log_error ("failed to convert keyparam: %s\n", gpg_strerror (rc));
104 return gpg_error (GPG_ERR_INV_DATA);
107 /* Get the passphrase now, cause key generation may take a while. */
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 const char *initial_errtext = NULL;
114 pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
115 pi2 = pi + (sizeof *pi + 100);
116 pi->max_length = 100;
117 pi->max_tries = 3;
118 pi2->max_length = 100;
119 pi2->max_tries = 3;
120 pi2->check_cb = reenter_compare_cb;
121 pi2->check_cb_arg = pi->pin;
123 next_try:
124 rc = agent_askpin (ctrl, text1, NULL, initial_errtext, pi);
125 initial_errtext = NULL;
126 if (!rc)
128 rc = agent_askpin (ctrl, text2, NULL, NULL, pi2);
129 if (rc == -1)
130 { /* The re-entered one did not match and the user did not
131 hit cancel. */
132 initial_errtext = _("does not match - try again");
133 goto next_try;
136 if (rc)
137 return rc;
138 if (!*pi->pin)
140 xfree (pi);
141 pi = NULL; /* User does not want a passphrase. */
145 rc = gcry_pk_genkey (&s_key, s_keyparam );
146 gcry_sexp_release (s_keyparam);
147 if (rc)
149 log_error ("key generation failed: %s\n", gpg_strerror (rc));
150 xfree (pi);
151 return rc;
154 /* break out the parts */
155 s_private = gcry_sexp_find_token (s_key, "private-key", 0);
156 if (!s_private)
158 log_error ("key generation failed: invalid return value\n");
159 gcry_sexp_release (s_key);
160 xfree (pi);
161 return gpg_error (GPG_ERR_INV_DATA);
163 s_public = gcry_sexp_find_token (s_key, "public-key", 0);
164 if (!s_public)
166 log_error ("key generation failed: invalid return value\n");
167 gcry_sexp_release (s_private);
168 gcry_sexp_release (s_key);
169 xfree (pi);
170 return gpg_error (GPG_ERR_INV_DATA);
172 gcry_sexp_release (s_key); s_key = NULL;
174 /* store the secret key */
175 if (DBG_CRYPTO)
176 log_debug ("storing private key\n");
177 rc = store_key (s_private, pi? pi->pin:NULL, 0);
178 xfree (pi); pi = NULL;
179 gcry_sexp_release (s_private);
180 if (rc)
182 gcry_sexp_release (s_public);
183 return rc;
186 /* return the public key */
187 if (DBG_CRYPTO)
188 log_debug ("returning public key\n");
189 len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, NULL, 0);
190 assert (len);
191 buf = xtrymalloc (len);
192 if (!buf)
194 gpg_error_t tmperr = out_of_core ();
195 gcry_sexp_release (s_private);
196 gcry_sexp_release (s_public);
197 return tmperr;
199 len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, buf, len);
200 assert (len);
201 put_membuf (outbuf, buf, len);
202 gcry_sexp_release (s_public);
203 xfree (buf);
205 return 0;
210 /* Apply a new passpahrse to the key S_SKEY and store it. */
212 agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey)
214 struct pin_entry_info_s *pi, *pi2;
215 int rc;
218 const char *text1 = _("Please enter the new passphrase");
219 const char *text2 = _("Please re-enter this passphrase");
220 const char *initial_errtext = NULL;
222 pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
223 pi2 = pi + (sizeof *pi + 100);
224 pi->max_length = 100;
225 pi->max_tries = 3;
226 pi2->max_length = 100;
227 pi2->max_tries = 3;
228 pi2->check_cb = reenter_compare_cb;
229 pi2->check_cb_arg = pi->pin;
231 next_try:
232 rc = agent_askpin (ctrl, text1, NULL, initial_errtext, pi);
233 if (!rc)
235 rc = agent_askpin (ctrl, text2, NULL, NULL, pi2);
236 if (rc == -1)
237 { /* The re-entered one did not match and the user did not
238 hit cancel. */
239 initial_errtext = _("does not match - try again");
240 goto next_try;
243 if (rc)
244 return rc;
245 if (!*pi->pin)
247 xfree (pi);
248 pi = NULL; /* User does not want a passphrase. */
252 rc = store_key (s_skey, pi? pi->pin:NULL, 1);
253 xfree (pi);
254 return 0;