agent/
[gnupg.git] / sm / certreqgen-ui.c
blob3e98b660fc81543d34b2abed1d88f9feb3f7e12d
1 /* certreqgen-ui.c - Simple user interface for certreqgen.c
2 * Copyright (C) 2007 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 3 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, see <http://www.gnu.org/licenses/>.
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <time.h>
27 #include <assert.h>
29 #include "gpgsm.h"
30 #include <gcrypt.h>
32 #include "i18n.h"
33 #include "ttyio.h"
34 #include "membuf.h"
37 /* Prompt for lines and append them to MB. */
38 static void
39 ask_mb_lines (membuf_t *mb, const char *prefix)
41 char *answer = NULL;
43 do
45 xfree (answer);
46 answer = tty_get ("> ");
47 tty_kill_prompt ();
48 trim_spaces (answer);
49 if (*answer)
51 put_membuf_str (mb, prefix);
52 put_membuf_str (mb, answer);
53 put_membuf (mb, "\n", 1);
56 while (*answer);
57 xfree (answer);
60 /* Helper to store stuff in a membuf. */
61 void
62 store_key_value_lf (membuf_t *mb, const char *key, const char *value)
64 put_membuf_str (mb, key);
65 put_membuf_str (mb, value);
66 put_membuf (mb, "\n", 1);
69 /* Helper tp store a membuf create by mb_ask_lines into MB. Returns
70 -1 on error. */
71 int
72 store_mb_lines (membuf_t *mb, membuf_t *lines)
74 char *p;
76 if (get_membuf_len (lines))
78 put_membuf (lines, "", 1);
79 p = get_membuf (lines, NULL);
80 if (!p)
81 return -1;
82 put_membuf_str (mb, p);
83 xfree (p);
85 return 0;
89 /* Chech whether we have a key for the key with HEXGRIP. Returns NULL
90 if not or a string describing the type of the key (RSA, ELG, DSA,
91 etc..). */
92 static const char *
93 check_keygrip (ctrl_t ctrl, const char *hexgrip)
95 gpg_error_t err;
96 ksba_sexp_t public;
97 size_t publiclen;
98 int algo;
100 if (hexgrip[0] == '&')
101 hexgrip++;
103 err = gpgsm_agent_readkey (ctrl, 0, hexgrip, &public);
104 if (err)
105 return NULL;
106 publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL);
108 get_pk_algo_from_canon_sexp (public, publiclen, &algo);
109 xfree (public);
111 switch (algo)
113 case GCRY_PK_RSA: return "RSA";
114 case GCRY_PK_DSA: return "DSA";
115 case GCRY_PK_ELG: return "ELG";
116 case GCRY_PK_ECDSA: return "ECDSA";
117 default: return NULL;
122 /* This function is used to create a certificate request from the
123 command line. In the past the similar gpgsm-gencert.sh script has
124 been used for it; however that scripts requires a full Unix shell
125 and thus is not suitable for the Windows port. So here is the
126 re-implementation. */
127 void
128 gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *output_fp)
130 gpg_error_t err;
131 char *answer;
132 int selection;
133 estream_t fp = NULL;
134 int method;
135 char *keytype_buffer = NULL;
136 const char *keytype;
137 char *keygrip = NULL;
138 unsigned int nbits;
139 int minbits = 1024;
140 int maxbits = 4096;
141 int defbits = 2048;
142 const char *keyusage;
143 char *subject_name;
144 membuf_t mb_email, mb_dns, mb_uri, mb_result;
145 char *result = NULL;
146 int i;
147 const char *s, *s2;
149 answer = NULL;
150 init_membuf (&mb_email, 100);
151 init_membuf (&mb_dns, 100);
152 init_membuf (&mb_uri, 100);
153 init_membuf (&mb_result, 512);
155 again:
156 /* Get the type of the key. */
157 tty_printf (_("Please select what kind of key you want:\n"));
158 tty_printf (_(" (%d) RSA\n"), 1 );
159 tty_printf (_(" (%d) Existing key\n"), 2 );
160 tty_printf (_(" (%d) Existing key from card\n"), 3 );
164 xfree (answer);
165 answer = tty_get (_("Your selection? "));
166 tty_kill_prompt ();
167 selection = *answer? atoi (answer): 1;
169 while (!(selection >= 1 && selection <= 3));
170 method = selection;
172 /* Get size of the key. */
173 if (method == 1)
175 keytype = "RSA";
176 for (;;)
178 xfree (answer);
179 answer = tty_getf (_("What keysize do you want? (%u) "), defbits);
180 tty_kill_prompt ();
181 trim_spaces (answer);
182 nbits = *answer? atoi (answer): defbits;
183 if (nbits < minbits || nbits > maxbits)
184 tty_printf(_("%s keysizes must be in the range %u-%u\n"),
185 "RSA", minbits, maxbits);
186 else
187 break; /* Okay. */
189 tty_printf (_("Requested keysize is %u bits\n"), nbits);
190 /* We round it up so that it better matches the word size. */
191 if (( nbits % 64))
193 nbits = ((nbits + 63) / 64) * 64;
194 tty_printf (_("rounded up to %u bits\n"), nbits);
197 else if (method == 2)
199 for (;;)
201 xfree (answer);
202 answer = tty_get (_("Enter the keygrip: "));
203 tty_kill_prompt ();
204 trim_spaces (answer);
206 if (!*answer)
207 goto again;
208 else if (strlen (answer) != 40 &&
209 !(answer[0] == '&' && strlen (answer+1) == 40))
210 tty_printf (_("Not a valid keygrip (expecting 40 hex digits)\n"));
211 else if (!(keytype = check_keygrip (ctrl, answer)) )
212 tty_printf (_("No key with this keygrip\n"));
213 else
214 break; /* Okay. */
216 xfree (keygrip);
217 keygrip = answer;
218 answer = NULL;
219 nbits = 1024; /* A dummy value is sufficient. */
221 else /* method == 3 */
223 char *serialno;
224 strlist_t keypairlist, sl;
225 int count;
227 err = gpgsm_agent_scd_serialno (ctrl, &serialno);
228 if (err)
230 tty_printf (_("error reading the card: %s\n"), gpg_strerror (err));
231 goto again;
233 tty_printf (_("Serial number of the card: %s\n"), serialno);
234 xfree (serialno);
236 err = gpgsm_agent_scd_keypairinfo (ctrl, &keypairlist);
237 if (err)
239 tty_printf (_("error reading the card: %s\n"), gpg_strerror (err));
240 goto again;
245 tty_printf (_("Available keys:\n"));
246 for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
247 tty_printf (" (%d) %s\n", count, sl->d);
248 xfree (answer);
249 answer = tty_get (_("Your selection? "));
250 tty_kill_prompt ();
251 trim_spaces (answer);
252 selection = atoi (answer);
254 while (!(selection > 0 && selection < count));
256 for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
257 if (count == selection)
258 break;
260 s = sl->d;
261 while (*s && !spacep (s))
262 s++;
263 while (spacep (s))
264 s++;
266 xfree (keygrip);
267 keygrip = NULL;
268 xfree (keytype_buffer);
269 keytype_buffer = xasprintf ("card:%s", s);
270 free_strlist (keypairlist);
271 keytype = keytype_buffer;
272 nbits = 1024; /* A dummy value is sufficient. */
275 /* Ask for the key usage. */
276 tty_printf (_("Possible actions for a %s key:\n"), "RSA");
277 tty_printf (_(" (%d) sign, encrypt\n"), 1 );
278 tty_printf (_(" (%d) sign\n"), 2 );
279 tty_printf (_(" (%d) encrypt\n"), 3 );
282 xfree (answer);
283 answer = tty_get (_("Your selection? "));
284 tty_kill_prompt ();
285 trim_spaces (answer);
286 selection = *answer? atoi (answer): 1;
287 switch (selection)
289 case 1: keyusage = "sign, encrypt"; break;
290 case 2: keyusage = "sign"; break;
291 case 3: keyusage = "encrypt"; break;
292 default: keyusage = NULL; break;
295 while (!keyusage);
297 /* Get the subject name. */
300 size_t erroff, errlen;
302 xfree (answer);
303 answer = tty_get (_("Enter the X.509 subject name: "));
304 tty_kill_prompt ();
305 trim_spaces (answer);
306 if (!*answer)
307 tty_printf (_("No subject name given\n"));
308 else if ( (err = ksba_dn_teststr (answer, 0, &erroff, &errlen)) )
310 if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME)
311 tty_printf (_("Invalid subject name label `%.*s'\n"),
312 (int)errlen, answer+erroff);
313 else
315 /* TRANSLATORS: The 22 in the second string is the
316 length of the first string up to the "%s". Please
317 adjust it do the length of your translation. The
318 second string is merely passed to atoi so you can
319 drop everything after the number. */
320 tty_printf (_("Invalid subject name `%s'\n"), answer);
321 tty_printf ("%*s^\n",
322 atoi (_("22 translator: see "
323 "certreg-ui.c:gpgsm_gencertreq_tty"))
324 + (int)erroff, "");
326 *answer = 0;
329 while (!*answer);
330 subject_name = answer;
331 answer = NULL;
333 /* Get the email addresses. */
334 tty_printf (_("Enter email addresses"));
335 tty_printf (_(" (end with an empty line):\n"));
336 ask_mb_lines (&mb_email, "Name-Email: ");
338 /* DNS names. */
339 tty_printf (_("Enter DNS names"));
340 tty_printf (_(" (optional; end with an empty line):\n"));
341 ask_mb_lines (&mb_email, "Name-DNS: ");
343 /* URIs. */
344 tty_printf (_("Enter URIs"));
345 tty_printf (_(" (optional; end with an empty line):\n"));
346 ask_mb_lines (&mb_email, "Name-URI: ");
349 /* Put it all together. */
350 store_key_value_lf (&mb_result, "Key-Type: ", keytype);
352 char numbuf[30];
353 snprintf (numbuf, sizeof numbuf, "%u", nbits);
354 store_key_value_lf (&mb_result, "Key-Length: ", numbuf);
356 store_key_value_lf (&mb_result, "Key-Usage: ", keyusage);
357 store_key_value_lf (&mb_result, "Name-DN: ", subject_name);
358 if (keygrip)
359 store_key_value_lf (&mb_result, "Key-Grip: ", keygrip);
360 if (store_mb_lines (&mb_result, &mb_email))
361 goto mem_error;
362 if (store_mb_lines (&mb_result, &mb_dns))
363 goto mem_error;
364 if (store_mb_lines (&mb_result, &mb_uri))
365 goto mem_error;
366 put_membuf (&mb_result, "", 1);
367 result = get_membuf (&mb_result, NULL);
368 if (!result)
369 goto mem_error;
371 tty_printf (_("Parameters to be used for the certificate request:\n"));
372 for (s=result; (s2 = strchr (s, '\n')); s = s2+1, i++)
373 tty_printf (" %.*s\n", (int)(s2-s), s);
374 tty_printf ("\n");
377 if (!tty_get_answer_is_yes ("Really create request? (y/N) "))
378 goto leave;
380 /* Now create a parameter file and generate the key. */
381 fp = es_fopenmem (0, "w+");
382 if (!fp)
384 log_error (_("error creating temporary file: %s\n"), strerror (errno));
385 goto leave;
387 es_fputs (result, fp);
388 es_rewind (fp);
389 tty_printf (_("Now creating certificate request. "
390 "This may take a while ...\n"));
392 int save_pem = ctrl->create_pem;
393 ctrl->create_pem = 1; /* Force creation of PEM. */
394 err = gpgsm_genkey (ctrl, fp, output_fp);
395 ctrl->create_pem = save_pem;
397 if (!err)
398 tty_printf (_("Ready. You should now send this request to your CA.\n"));
401 goto leave;
402 mem_error:
403 log_error (_("resource problem: out of core\n"));
404 leave:
405 es_fclose (fp);
406 xfree (answer);
407 xfree (subject_name);
408 xfree (keytype_buffer);
409 xfree (keygrip);
410 xfree (get_membuf (&mb_email, NULL));
411 xfree (get_membuf (&mb_dns, NULL));
412 xfree (get_membuf (&mb_uri, NULL));
413 xfree (get_membuf (&mb_result, NULL));
414 xfree (result);