chiark / gitweb /
dirmngr: Fix for --disable-libdns usage.
[gnupg2.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 <https://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   const char *s, *s2;
151   int selfsigned;
152
153   answer = NULL;
154   init_membuf (&mb_email, 100);
155   init_membuf (&mb_dns, 100);
156   init_membuf (&mb_uri, 100);
157   init_membuf (&mb_result, 512);
158
159  again:
160   /* Get the type of the key.  */
161   tty_printf (_("Please select what kind of key you want:\n"));
162   tty_printf (_("   (%d) RSA\n"), 1 );
163   tty_printf (_("   (%d) Existing key\n"), 2 );
164   tty_printf (_("   (%d) Existing key from card\n"), 3 );
165
166   do
167     {
168       xfree (answer);
169       answer = tty_get (_("Your selection? "));
170       tty_kill_prompt ();
171       selection = *answer? atoi (answer): 1;
172     }
173   while (!(selection >= 1 && selection <= 3));
174   method = selection;
175
176   /* Get  size of the key.  */
177   if (method == 1)
178     {
179       keytype = "RSA";
180       for (;;)
181         {
182           xfree (answer);
183           answer = tty_getf (_("What keysize do you want? (%u) "), defbits);
184           tty_kill_prompt ();
185           trim_spaces (answer);
186           nbits = *answer? atoi (answer): defbits;
187           if (nbits < minbits || nbits > maxbits)
188             tty_printf(_("%s keysizes must be in the range %u-%u\n"),
189                          "RSA", minbits, maxbits);
190           else
191             break; /* Okay.  */
192         }
193       tty_printf (_("Requested keysize is %u bits\n"), nbits);
194       /* We round it up so that it better matches the word size.  */
195       if (( nbits % 64))
196         {
197           nbits = ((nbits + 63) / 64) * 64;
198           tty_printf (_("rounded up to %u bits\n"), nbits);
199         }
200     }
201   else if (method == 2)
202     {
203       for (;;)
204         {
205           xfree (answer);
206           answer = tty_get (_("Enter the keygrip: "));
207           tty_kill_prompt ();
208           trim_spaces (answer);
209
210           if (!*answer)
211             goto again;
212           else if (strlen (answer) != 40 &&
213                    !(answer[0] == '&' && strlen (answer+1) == 40))
214             tty_printf (_("Not a valid keygrip (expecting 40 hex digits)\n"));
215           else if (!(keytype = check_keygrip (ctrl, answer)) )
216             tty_printf (_("No key with this keygrip\n"));
217           else
218             break; /* Okay.  */
219         }
220       xfree (keygrip);
221       keygrip = answer;
222       answer = NULL;
223       nbits = 1024; /* A dummy value is sufficient.  */
224     }
225   else /* method == 3 */
226     {
227       char *serialno;
228       strlist_t keypairlist, sl;
229       int count;
230
231       err = gpgsm_agent_scd_serialno (ctrl, &serialno);
232       if (err)
233         {
234           tty_printf (_("error reading the card: %s\n"), gpg_strerror (err));
235           goto again;
236         }
237       tty_printf (_("Serial number of the card: %s\n"), serialno);
238       xfree (serialno);
239
240       err = gpgsm_agent_scd_keypairinfo (ctrl, &keypairlist);
241       if (err)
242         {
243           tty_printf (_("error reading the card: %s\n"), gpg_strerror (err));
244           goto again;
245         }
246
247       do
248         {
249           tty_printf (_("Available keys:\n"));
250           for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
251             tty_printf ("   (%d) %s\n", count, sl->d);
252           xfree (answer);
253           answer = tty_get (_("Your selection? "));
254           tty_kill_prompt ();
255           trim_spaces (answer);
256           selection = atoi (answer);
257         }
258       while (!(selection > 0 && selection < count));
259
260       for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
261         if (count == selection)
262           break;
263
264       s = sl->d;
265       while (*s && !spacep (s))
266         s++;
267       while (spacep (s))
268         s++;
269
270       xfree (keygrip);
271       keygrip = NULL;
272       xfree (keytype_buffer);
273       keytype_buffer = xasprintf ("card:%s", s);
274       free_strlist (keypairlist);
275       keytype = keytype_buffer;
276       nbits = 1024; /* A dummy value is sufficient.  */
277     }
278
279   /* Ask for the key usage.  */
280   tty_printf (_("Possible actions for a %s key:\n"), "RSA");
281   tty_printf (_("   (%d) sign, encrypt\n"), 1 );
282   tty_printf (_("   (%d) sign\n"), 2 );
283   tty_printf (_("   (%d) encrypt\n"), 3 );
284   do
285     {
286       xfree (answer);
287       answer = tty_get (_("Your selection? "));
288       tty_kill_prompt ();
289       trim_spaces (answer);
290       selection = *answer? atoi (answer): 1;
291       switch (selection)
292         {
293         case 1: keyusage = "sign, encrypt"; break;
294         case 2: keyusage = "sign"; break;
295         case 3: keyusage = "encrypt"; break;
296         default: keyusage = NULL; break;
297         }
298     }
299   while (!keyusage);
300
301   /* Get the subject name.  */
302   do
303     {
304       size_t erroff, errlen;
305
306       xfree (answer);
307       answer = tty_get (_("Enter the X.509 subject name: "));
308       tty_kill_prompt ();
309       trim_spaces (answer);
310       if (!*answer)
311         tty_printf (_("No subject name given\n"));
312       else if ( (err = ksba_dn_teststr (answer, 0, &erroff, &errlen)) )
313         {
314           if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME)
315             tty_printf (_("Invalid subject name label '%.*s'\n"),
316                         (int)errlen, answer+erroff);
317           else
318             {
319               /* TRANSLATORS: The 22 in the second string is the
320                  length of the first string up to the "%s".  Please
321                  adjust it do the length of your translation.  The
322                  second string is merely passed to atoi so you can
323                  drop everything after the number.  */
324               tty_printf (_("Invalid subject name '%s'\n"), answer);
325               tty_printf ("%*s^\n",
326                           atoi (_("22 translator: see "
327                                   "certreg-ui.c:gpgsm_gencertreq_tty"))
328                           + (int)erroff, "");
329             }
330           *answer = 0;
331         }
332     }
333   while (!*answer);
334   subject_name = answer;
335   answer = NULL;
336
337   /* Get the email addresses. */
338   tty_printf (_("Enter email addresses"));
339   tty_printf (_(" (end with an empty line):\n"));
340   ask_mb_lines (&mb_email, "Name-Email: ");
341
342   /* DNS names.  */
343   tty_printf (_("Enter DNS names"));
344   tty_printf (_(" (optional; end with an empty line):\n"));
345   ask_mb_lines (&mb_dns, "Name-DNS: ");
346
347   /* URIs.  */
348   tty_printf (_("Enter URIs"));
349   tty_printf (_(" (optional; end with an empty line):\n"));
350   ask_mb_lines (&mb_uri, "Name-URI: ");
351
352
353   /* Want a self-signed certificate?  */
354   selfsigned = tty_get_answer_is_yes
355     (_("Create self-signed certificate? (y/N) "));
356
357
358   /* Put it all together.  */
359   store_key_value_lf (&mb_result, "Key-Type: ", keytype);
360   {
361     char numbuf[30];
362     snprintf (numbuf, sizeof numbuf, "%u", nbits);
363     store_key_value_lf (&mb_result, "Key-Length: ", numbuf);
364   }
365   if (keygrip)
366     store_key_value_lf (&mb_result, "Key-Grip: ", keygrip);
367   store_key_value_lf (&mb_result, "Key-Usage: ", keyusage);
368   if (selfsigned)
369     store_key_value_lf (&mb_result, "Serial: ", "random");
370   store_key_value_lf (&mb_result, "Name-DN: ", subject_name);
371   if (store_mb_lines (&mb_result, &mb_email))
372     goto mem_error;
373   if (store_mb_lines (&mb_result, &mb_dns))
374     goto mem_error;
375   if (store_mb_lines (&mb_result, &mb_uri))
376     goto mem_error;
377   put_membuf (&mb_result, "", 1);
378   result = get_membuf (&mb_result, NULL);
379   if (!result)
380     goto mem_error;
381
382   tty_printf (_("These parameters are used:\n"));
383   for (s=result; (s2 = strchr (s, '\n')); s = s2+1)
384     tty_printf ("    %.*s\n", (int)(s2-s), s);
385   tty_printf ("\n");
386
387   if (!tty_get_answer_is_yes ("Proceed with creation? (y/N) "))
388     goto leave;
389
390   /* Now create a parameter file and generate the key.  */
391   fp = es_fopenmem (0, "w+");
392   if (!fp)
393     {
394       log_error (_("error creating temporary file: %s\n"), strerror (errno));
395       goto leave;
396     }
397   es_fputs (result, fp);
398   es_rewind (fp);
399   if (selfsigned)
400     tty_printf ("%s", _("Now creating self-signed certificate.  "));
401   else
402     tty_printf ("%s", _("Now creating certificate request.  "));
403   tty_printf ("%s", _("This may take a while ...\n"));
404
405   {
406     int save_pem = ctrl->create_pem;
407     ctrl->create_pem = 1; /* Force creation of PEM. */
408     err = gpgsm_genkey (ctrl, fp, output_stream);
409     ctrl->create_pem = save_pem;
410   }
411   if (!err)
412     {
413       if (selfsigned)
414         tty_printf (_("Ready.\n"));
415       else
416         tty_printf
417           (_("Ready.  You should now send this request to your CA.\n"));
418     }
419
420
421   goto leave;
422  mem_error:
423   log_error (_("resource problem: out of core\n"));
424  leave:
425   es_fclose (fp);
426   xfree (answer);
427   xfree (subject_name);
428   xfree (keytype_buffer);
429   xfree (keygrip);
430   xfree (get_membuf (&mb_email, NULL));
431   xfree (get_membuf (&mb_dns, NULL));
432   xfree (get_membuf (&mb_uri, NULL));
433   xfree (get_membuf (&mb_result, NULL));
434   xfree (result);
435 }