gpg: More fix of get_best_pubkey_byname.
[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 <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 "../common/i18n.h"
33 #include "../common/ttyio.h"
34 #include "../common/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 /* Check 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   int algo;
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   algo = get_pk_algo_from_canon_sexp (public, publiclen);
109   xfree (public);
110
111   switch (algo)
112     {
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_EDDSA: return "ECDSA";
117     default: return NULL;
118     }
119 }
120
121
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, estream_t output_stream)
129 {
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 = 3072;
142   const char *keyusage;
143   char *subject_name;
144   membuf_t mb_email, mb_dns, mb_uri, mb_result;
145   char *result = NULL;
146   const char *s, *s2;
147   int selfsigned;
148
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);
154
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 );
161
162   do
163     {
164       xfree (answer);
165       answer = tty_get (_("Your selection? "));
166       tty_kill_prompt ();
167       selection = *answer? atoi (answer): 1;
168     }
169   while (!(selection >= 1 && selection <= 3));
170   method = selection;
171
172   /* Get  size of the key.  */
173   if (method == 1)
174     {
175       keytype = "RSA";
176       for (;;)
177         {
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.  */
188         }
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))
192         {
193           nbits = ((nbits + 63) / 64) * 64;
194           tty_printf (_("rounded up to %u bits\n"), nbits);
195         }
196     }
197   else if (method == 2)
198     {
199       for (;;)
200         {
201           xfree (answer);
202           answer = tty_get (_("Enter the keygrip: "));
203           tty_kill_prompt ();
204           trim_spaces (answer);
205
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.  */
215         }
216       xfree (keygrip);
217       keygrip = answer;
218       answer = NULL;
219       nbits = 1024; /* A dummy value is sufficient.  */
220     }
221   else /* method == 3 */
222     {
223       char *serialno;
224       strlist_t keypairlist, sl;
225       int count;
226
227       err = gpgsm_agent_scd_serialno (ctrl, &serialno);
228       if (err)
229         {
230           tty_printf (_("error reading the card: %s\n"), gpg_strerror (err));
231           goto again;
232         }
233       tty_printf (_("Serial number of the card: %s\n"), serialno);
234       xfree (serialno);
235
236       err = gpgsm_agent_scd_keypairinfo (ctrl, &keypairlist);
237       if (err)
238         {
239           tty_printf (_("error reading the card: %s\n"), gpg_strerror (err));
240           goto again;
241         }
242
243       do
244         {
245           tty_printf (_("Available keys:\n"));
246           for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
247             {
248               ksba_sexp_t pkey;
249               gcry_sexp_t s_pkey;
250               char *algostr = NULL;
251               const char *keyref;
252               int any = 0;
253
254               keyref = strchr (sl->d, ' ');
255               if (keyref)
256                 {
257                   keyref++;
258                   if (!gpgsm_agent_readkey (ctrl, 1, keyref, &pkey))
259                     {
260                       if (!gcry_sexp_new (&s_pkey, pkey, 0, 0))
261                         algostr = pubkey_algo_string (s_pkey, NULL);
262                       gcry_sexp_release (s_pkey);
263                     }
264                   xfree (pkey);
265                 }
266               tty_printf ("   (%d) %s %s", count, sl->d, algostr);
267               if ((sl->flags & GCRY_PK_USAGE_CERT))
268                 {
269                   tty_printf ("%scert", any?",":" (");
270                   any = 1;
271                 }
272               if ((sl->flags & GCRY_PK_USAGE_SIGN))
273                 {
274                   tty_printf ("%ssign", any?",":" (");
275                   any = 1;
276                 }
277               if ((sl->flags & GCRY_PK_USAGE_AUTH))
278                 {
279                   tty_printf ("%sauth", any?",":" (");
280                   any = 1;
281                 }
282               if ((sl->flags & GCRY_PK_USAGE_ENCR))
283                 {
284                   tty_printf ("%sencr", any?",":" (");
285                   any = 1;
286                 }
287               tty_printf ("%s\n", any?")":"");
288               xfree (algostr);
289             }
290           xfree (answer);
291           answer = tty_get (_("Your selection? "));
292           tty_kill_prompt ();
293           trim_spaces (answer);
294           selection = atoi (answer);
295         }
296       while (!(selection > 0 && selection < count));
297
298       for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
299         if (count == selection)
300           break;
301
302       s = sl->d;
303       while (*s && !spacep (s))
304         s++;
305       while (spacep (s))
306         s++;
307
308       xfree (keygrip);
309       keygrip = NULL;
310       xfree (keytype_buffer);
311       keytype_buffer = xasprintf ("card:%s", s);
312       free_strlist (keypairlist);
313       keytype = keytype_buffer;
314       nbits = 1024; /* A dummy value is sufficient.  */
315     }
316
317   /* Ask for the key usage.  */
318   tty_printf (_("Possible actions for a %s key:\n"), "RSA");
319   tty_printf (_("   (%d) sign, encrypt\n"), 1 );
320   tty_printf (_("   (%d) sign\n"), 2 );
321   tty_printf (_("   (%d) encrypt\n"), 3 );
322   do
323     {
324       xfree (answer);
325       answer = tty_get (_("Your selection? "));
326       tty_kill_prompt ();
327       trim_spaces (answer);
328       selection = *answer? atoi (answer): 1;
329       switch (selection)
330         {
331         case 1: keyusage = "sign, encrypt"; break;
332         case 2: keyusage = "sign"; break;
333         case 3: keyusage = "encrypt"; break;
334         default: keyusage = NULL; break;
335         }
336     }
337   while (!keyusage);
338
339   /* Get the subject name.  */
340   do
341     {
342       size_t erroff, errlen;
343
344       xfree (answer);
345       answer = tty_get (_("Enter the X.509 subject name: "));
346       tty_kill_prompt ();
347       trim_spaces (answer);
348       if (!*answer)
349         tty_printf (_("No subject name given\n"));
350       else if ( (err = ksba_dn_teststr (answer, 0, &erroff, &errlen)) )
351         {
352           if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME)
353             tty_printf (_("Invalid subject name label '%.*s'\n"),
354                         (int)errlen, answer+erroff);
355           else
356             {
357               /* TRANSLATORS: The 22 in the second string is the
358                  length of the first string up to the "%s".  Please
359                  adjust it do the length of your translation.  The
360                  second string is merely passed to atoi so you can
361                  drop everything after the number.  */
362               tty_printf (_("Invalid subject name '%s'\n"), answer);
363               tty_printf ("%*s^\n",
364                           atoi (_("22 translator: see "
365                                   "certreg-ui.c:gpgsm_gencertreq_tty"))
366                           + (int)erroff, "");
367             }
368           *answer = 0;
369         }
370     }
371   while (!*answer);
372   subject_name = answer;
373   answer = NULL;
374
375   /* Get the email addresses. */
376   tty_printf (_("Enter email addresses"));
377   tty_printf (_(" (end with an empty line):\n"));
378   ask_mb_lines (&mb_email, "Name-Email: ");
379
380   /* DNS names.  */
381   tty_printf (_("Enter DNS names"));
382   tty_printf (_(" (optional; end with an empty line):\n"));
383   ask_mb_lines (&mb_dns, "Name-DNS: ");
384
385   /* URIs.  */
386   tty_printf (_("Enter URIs"));
387   tty_printf (_(" (optional; end with an empty line):\n"));
388   ask_mb_lines (&mb_uri, "Name-URI: ");
389
390
391   /* Want a self-signed certificate?  */
392   selfsigned = tty_get_answer_is_yes
393     (_("Create self-signed certificate? (y/N) "));
394
395
396   /* Put it all together.  */
397   store_key_value_lf (&mb_result, "Key-Type: ", keytype);
398   {
399     char numbuf[30];
400     snprintf (numbuf, sizeof numbuf, "%u", nbits);
401     store_key_value_lf (&mb_result, "Key-Length: ", numbuf);
402   }
403   if (keygrip)
404     store_key_value_lf (&mb_result, "Key-Grip: ", keygrip);
405   store_key_value_lf (&mb_result, "Key-Usage: ", keyusage);
406   if (selfsigned)
407     store_key_value_lf (&mb_result, "Serial: ", "random");
408   store_key_value_lf (&mb_result, "Name-DN: ", subject_name);
409   if (store_mb_lines (&mb_result, &mb_email))
410     goto mem_error;
411   if (store_mb_lines (&mb_result, &mb_dns))
412     goto mem_error;
413   if (store_mb_lines (&mb_result, &mb_uri))
414     goto mem_error;
415   put_membuf (&mb_result, "", 1);
416   result = get_membuf (&mb_result, NULL);
417   if (!result)
418     goto mem_error;
419
420   tty_printf (_("These parameters are used:\n"));
421   for (s=result; (s2 = strchr (s, '\n')); s = s2+1)
422     tty_printf ("    %.*s\n", (int)(s2-s), s);
423   tty_printf ("\n");
424
425   if (!tty_get_answer_is_yes ("Proceed with creation? (y/N) "))
426     goto leave;
427
428   /* Now create a parameter file and generate the key.  */
429   fp = es_fopenmem (0, "w+");
430   if (!fp)
431     {
432       log_error (_("error creating temporary file: %s\n"), strerror (errno));
433       goto leave;
434     }
435   es_fputs (result, fp);
436   es_rewind (fp);
437   if (selfsigned)
438     tty_printf ("%s", _("Now creating self-signed certificate.  "));
439   else
440     tty_printf ("%s", _("Now creating certificate request.  "));
441   tty_printf ("%s", _("This may take a while ...\n"));
442
443   {
444     int save_pem = ctrl->create_pem;
445     ctrl->create_pem = 1; /* Force creation of PEM. */
446     err = gpgsm_genkey (ctrl, fp, output_stream);
447     ctrl->create_pem = save_pem;
448   }
449   if (!err)
450     {
451       if (selfsigned)
452         tty_printf (_("Ready.\n"));
453       else
454         tty_printf
455           (_("Ready.  You should now send this request to your CA.\n"));
456     }
457
458
459   goto leave;
460  mem_error:
461   log_error (_("resource problem: out of core\n"));
462  leave:
463   es_fclose (fp);
464   xfree (answer);
465   xfree (subject_name);
466   xfree (keytype_buffer);
467   xfree (keygrip);
468   xfree (get_membuf (&mb_email, NULL));
469   xfree (get_membuf (&mb_dns, NULL));
470   xfree (get_membuf (&mb_uri, NULL));
471   xfree (get_membuf (&mb_result, NULL));
472   xfree (result);
473 }