ECC Fixes.
[gnupg.git] / sm / certreqgen-ui.c
1 /* certreqgen-ui.c - Simple user interface for certreqgen.c
2  * Copyright (C) 2007, 2010, 2011 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 <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>
28
29 #include "gpgsm.h"
30 #include <gcrypt.h>
31
32 #include "i18n.h"
33 #include "ttyio.h"
34 #include "membuf.h"
35
36
37 /* Prompt for lines and append them to MB.  */
38 static void
39 ask_mb_lines (membuf_t *mb, const char *prefix)
40 {
41   char *answer = NULL;
42
43   do
44     {
45       xfree (answer);
46       answer = tty_get ("> ");
47       tty_kill_prompt ();
48       trim_spaces (answer);
49       if (*answer)
50         {
51           put_membuf_str (mb, prefix);
52           put_membuf_str (mb, answer);
53           put_membuf (mb, "\n", 1);
54         }
55     }
56   while (*answer);
57   xfree (answer);
58 }
59
60 /* Helper to store stuff in a membuf.  */
61 void
62 store_key_value_lf (membuf_t *mb, const char *key, const char *value)
63 {
64   put_membuf_str (mb, key);
65   put_membuf_str (mb, value);
66   put_membuf (mb, "\n", 1);
67 }
68
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)
73 {
74   char *p;
75
76   if (get_membuf_len (lines))
77     {
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);
84     }
85   return 0;
86 }
87
88
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)
94 {
95   gpg_error_t err;
96   ksba_sexp_t public;
97   size_t publiclen;
98   const char *algostr;
99
100   if (hexgrip[0] == '&')
101     hexgrip++;
102
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);
107
108   get_pk_algo_from_canon_sexp (public, publiclen, &algostr);
109   xfree (public);
110
111   if (!algostr)
112     return NULL;
113   else if (!strcmp (algostr, "rsa"))
114     return "RSA";
115   else if (!strcmp (algostr, "dsa"))
116     return "DSA";
117   else if (!strcmp (algostr, "elg"))
118     return "ELG";
119   else if (!strcmp (algostr, "ecdsa"))
120     return "ECDSA";
121   else
122     return NULL;
123 }
124
125
126 /* This function is used to create a certificate request from the
127    command line.  In the past the similar gpgsm-gencert.sh script has
128    been used for it; however that scripts requires a full Unix shell
129    and thus is not suitable for the Windows port.  So here is the
130    re-implementation.  */
131 void
132 gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream)
133 {
134   gpg_error_t err;
135   char *answer;
136   int selection;
137   estream_t fp = NULL;
138   int method;
139   char *keytype_buffer = NULL;
140   const char *keytype;
141   char *keygrip = NULL;
142   unsigned int nbits;
143   int minbits = 1024;
144   int maxbits = 4096;
145   int defbits = 2048;
146   const char *keyusage;
147   char *subject_name;
148   membuf_t mb_email, mb_dns, mb_uri, mb_result;
149   char *result = NULL;
150   int i;
151   const char *s, *s2;
152   int selfsigned;
153
154   answer = NULL;
155   init_membuf (&mb_email, 100);
156   init_membuf (&mb_dns, 100);
157   init_membuf (&mb_uri, 100);
158   init_membuf (&mb_result, 512);
159
160  again:
161   /* Get the type of the key.  */
162   tty_printf (_("Please select what kind of key you want:\n"));
163   tty_printf (_("   (%d) RSA\n"), 1 );
164   tty_printf (_("   (%d) Existing key\n"), 2 );
165   tty_printf (_("   (%d) Existing key from card\n"), 3 );
166
167   do
168     {
169       xfree (answer);
170       answer = tty_get (_("Your selection? "));
171       tty_kill_prompt ();
172       selection = *answer? atoi (answer): 1;
173     }
174   while (!(selection >= 1 && selection <= 3));
175   method = selection;
176
177   /* Get  size of the key.  */
178   if (method == 1)
179     {
180       keytype = "RSA";
181       for (;;)
182         {
183           xfree (answer);
184           answer = tty_getf (_("What keysize do you want? (%u) "), defbits);
185           tty_kill_prompt ();
186           trim_spaces (answer);
187           nbits = *answer? atoi (answer): defbits;
188           if (nbits < minbits || nbits > maxbits)
189             tty_printf(_("%s keysizes must be in the range %u-%u\n"),
190                          "RSA", minbits, maxbits);
191           else
192             break; /* Okay.  */
193         }
194       tty_printf (_("Requested keysize is %u bits\n"), nbits);
195       /* We round it up so that it better matches the word size.  */
196       if (( nbits % 64))
197         {
198           nbits = ((nbits + 63) / 64) * 64;
199           tty_printf (_("rounded up to %u bits\n"), nbits);
200         }
201     }
202   else if (method == 2)
203     {
204       for (;;)
205         {
206           xfree (answer);
207           answer = tty_get (_("Enter the keygrip: "));
208           tty_kill_prompt ();
209           trim_spaces (answer);
210
211           if (!*answer)
212             goto again;
213           else if (strlen (answer) != 40 &&
214                    !(answer[0] == '&' && strlen (answer+1) == 40))
215             tty_printf (_("Not a valid keygrip (expecting 40 hex digits)\n"));
216           else if (!(keytype = check_keygrip (ctrl, answer)) )
217             tty_printf (_("No key with this keygrip\n"));
218           else
219             break; /* Okay.  */
220         }
221       xfree (keygrip);
222       keygrip = answer;
223       answer = NULL;
224       nbits = 1024; /* A dummy value is sufficient.  */
225     }
226   else /* method == 3 */
227     {
228       char *serialno;
229       strlist_t keypairlist, sl;
230       int count;
231
232       err = gpgsm_agent_scd_serialno (ctrl, &serialno);
233       if (err)
234         {
235           tty_printf (_("error reading the card: %s\n"), gpg_strerror (err));
236           goto again;
237         }
238       tty_printf (_("Serial number of the card: %s\n"), serialno);
239       xfree (serialno);
240
241       err = gpgsm_agent_scd_keypairinfo (ctrl, &keypairlist);
242       if (err)
243         {
244           tty_printf (_("error reading the card: %s\n"), gpg_strerror (err));
245           goto again;
246         }
247
248       do
249         {
250           tty_printf (_("Available keys:\n"));
251           for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
252             tty_printf ("   (%d) %s\n", count, sl->d);
253           xfree (answer);
254           answer = tty_get (_("Your selection? "));
255           tty_kill_prompt ();
256           trim_spaces (answer);
257           selection = atoi (answer);
258         }
259       while (!(selection > 0 && selection < count));
260
261       for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
262         if (count == selection)
263           break;
264
265       s = sl->d;
266       while (*s && !spacep (s))
267         s++;
268       while (spacep (s))
269         s++;
270
271       xfree (keygrip);
272       keygrip = NULL;
273       xfree (keytype_buffer);
274       keytype_buffer = xasprintf ("card:%s", s);
275       free_strlist (keypairlist);
276       keytype = keytype_buffer;
277       nbits = 1024; /* A dummy value is sufficient.  */
278     }
279
280   /* Ask for the key usage.  */
281   tty_printf (_("Possible actions for a %s key:\n"), "RSA");
282   tty_printf (_("   (%d) sign, encrypt\n"), 1 );
283   tty_printf (_("   (%d) sign\n"), 2 );
284   tty_printf (_("   (%d) encrypt\n"), 3 );
285   do
286     {
287       xfree (answer);
288       answer = tty_get (_("Your selection? "));
289       tty_kill_prompt ();
290       trim_spaces (answer);
291       selection = *answer? atoi (answer): 1;
292       switch (selection)
293         {
294         case 1: keyusage = "sign, encrypt"; break;
295         case 2: keyusage = "sign"; break;
296         case 3: keyusage = "encrypt"; break;
297         default: keyusage = NULL; break;
298         }
299     }
300   while (!keyusage);
301
302   /* Get the subject name.  */
303   do
304     {
305       size_t erroff, errlen;
306
307       xfree (answer);
308       answer = tty_get (_("Enter the X.509 subject name: "));
309       tty_kill_prompt ();
310       trim_spaces (answer);
311       if (!*answer)
312         tty_printf (_("No subject name given\n"));
313       else if ( (err = ksba_dn_teststr (answer, 0, &erroff, &errlen)) )
314         {
315           if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME)
316             tty_printf (_("Invalid subject name label '%.*s'\n"),
317                         (int)errlen, answer+erroff);
318           else
319             {
320               /* TRANSLATORS: The 22 in the second string is the
321                  length of the first string up to the "%s".  Please
322                  adjust it do the length of your translation.  The
323                  second string is merely passed to atoi so you can
324                  drop everything after the number.  */
325               tty_printf (_("Invalid subject name '%s'\n"), answer);
326               tty_printf ("%*s^\n",
327                           atoi (_("22 translator: see "
328                                   "certreg-ui.c:gpgsm_gencertreq_tty"))
329                           + (int)erroff, "");
330             }
331           *answer = 0;
332         }
333     }
334   while (!*answer);
335   subject_name = answer;
336   answer = NULL;
337
338   /* Get the email addresses. */
339   tty_printf (_("Enter email addresses"));
340   tty_printf (_(" (end with an empty line):\n"));
341   ask_mb_lines (&mb_email, "Name-Email: ");
342
343   /* DNS names.  */
344   tty_printf (_("Enter DNS names"));
345   tty_printf (_(" (optional; end with an empty line):\n"));
346   ask_mb_lines (&mb_dns, "Name-DNS: ");
347
348   /* URIs.  */
349   tty_printf (_("Enter URIs"));
350   tty_printf (_(" (optional; end with an empty line):\n"));
351   ask_mb_lines (&mb_uri, "Name-URI: ");
352
353
354   /* Want a self-signed certificate?  */
355   selfsigned = tty_get_answer_is_yes
356     (_("Create self-signed certificate? (y/N) "));
357
358
359   /* Put it all together.  */
360   store_key_value_lf (&mb_result, "Key-Type: ", keytype);
361   {
362     char numbuf[30];
363     snprintf (numbuf, sizeof numbuf, "%u", nbits);
364     store_key_value_lf (&mb_result, "Key-Length: ", numbuf);
365   }
366   if (keygrip)
367     store_key_value_lf (&mb_result, "Key-Grip: ", keygrip);
368   store_key_value_lf (&mb_result, "Key-Usage: ", keyusage);
369   if (selfsigned)
370     store_key_value_lf (&mb_result, "Serial: ", "random");
371   store_key_value_lf (&mb_result, "Name-DN: ", subject_name);
372   if (store_mb_lines (&mb_result, &mb_email))
373     goto mem_error;
374   if (store_mb_lines (&mb_result, &mb_dns))
375     goto mem_error;
376   if (store_mb_lines (&mb_result, &mb_uri))
377     goto mem_error;
378   put_membuf (&mb_result, "", 1);
379   result = get_membuf (&mb_result, NULL);
380   if (!result)
381     goto mem_error;
382
383   tty_printf (_("These parameters are used:\n"));
384   for (s=result; (s2 = strchr (s, '\n')); s = s2+1, i++)
385     tty_printf ("    %.*s\n", (int)(s2-s), s);
386   tty_printf ("\n");
387
388   if (!tty_get_answer_is_yes ("Proceed with creation? (y/N) "))
389     goto leave;
390
391   /* Now create a parameter file and generate the key.  */
392   fp = es_fopenmem (0, "w+");
393   if (!fp)
394     {
395       log_error (_("error creating temporary file: %s\n"), strerror (errno));
396       goto leave;
397     }
398   es_fputs (result, fp);
399   es_rewind (fp);
400   if (selfsigned)
401     tty_printf ("%s", _("Now creating self-signed certificate.  "));
402   else
403     tty_printf ("%s", _("Now creating certificate request.  "));
404   tty_printf ("%s", _("This may take a while ...\n"));
405
406   {
407     int save_pem = ctrl->create_pem;
408     ctrl->create_pem = 1; /* Force creation of PEM. */
409     err = gpgsm_genkey (ctrl, fp, output_stream);
410     ctrl->create_pem = save_pem;
411   }
412   if (!err)
413     {
414       if (selfsigned)
415         tty_printf (_("Ready.\n"));
416       else
417         tty_printf
418           (_("Ready.  You should now send this request to your CA.\n"));
419     }
420
421
422   goto leave;
423  mem_error:
424   log_error (_("resource problem: out of core\n"));
425  leave:
426   es_fclose (fp);
427   xfree (answer);
428   xfree (subject_name);
429   xfree (keytype_buffer);
430   xfree (keygrip);
431   xfree (get_membuf (&mb_email, NULL));
432   xfree (get_membuf (&mb_dns, NULL));
433   xfree (get_membuf (&mb_uri, NULL));
434   xfree (get_membuf (&mb_result, NULL));
435   xfree (result);
436 }