New gpgsm server option no-encrypt-to.
[gnupg.git] / sm / certreqgen-ui.c
1 /* certreqgen-ui.c - Simple user interface for certreqgen.c
2  * Copyright (C) 2007 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 /* This function is used to create a certificate request from the
90    command line.  In the past the similar gpgsm-gencert.sh script has
91    been used for it; however that scripts requires a full Unix shell
92    and thus is not suitable for the Windows port.  So here is the
93    re-implementation.  */
94 void
95 gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *output_fp)
96 {
97   gpg_error_t err;
98   char *answer;
99   int selection;
100   estream_t fp = NULL;
101   int method;
102   char *keytype;
103   char *keygrip = NULL;
104   unsigned int nbits;
105   int minbits = 1024;
106   int maxbits = 4096;
107   int defbits = 2048;
108   const char *keyusage;
109   char *subject_name;
110   membuf_t mb_email, mb_dns, mb_uri, mb_result;
111   char *result = NULL;
112   int i;
113   const char *s, *s2;
114
115   init_membuf (&mb_email, 100);
116   init_membuf (&mb_dns, 100);
117   init_membuf (&mb_uri, 100);
118   init_membuf (&mb_result, 512);
119
120   /* Get the type of the key.  */
121   tty_printf (_("Please select what kind of key you want:\n"));
122   tty_printf (_("   (%d) RSA\n"), 1 );
123   tty_printf (_("   (%d) Existing key\n"), 2 );
124   tty_printf (_("   (%d) Existing key from card\n"), 3 );
125
126   do
127     {
128       answer = tty_get (_("Your selection? "));
129       tty_kill_prompt ();
130       selection = *answer? atoi (answer): 1;
131       xfree (answer);
132     }
133   while (!(selection >= 1 && selection <= 3));
134   method = selection;
135
136   /* Get  size of the key.  */
137   if (method == 1)
138     {
139       keytype = xstrdup ("RSA");
140       for (;;)
141         {
142           answer = tty_getf (_("What keysize do you want? (%u) "), defbits);
143           tty_kill_prompt ();
144           nbits = *answer? atoi (answer): defbits;
145           xfree (answer);
146           if (nbits < minbits || nbits > maxbits)
147             tty_printf(_("%s keysizes must be in the range %u-%u\n"),
148                          "RSA", minbits, maxbits);
149           else
150             break; /* Okay.  */
151         }
152       tty_printf (_("Requested keysize is %u bits\n"), nbits);
153       /* We round it up so that it better matches the word size.  */
154       if (( nbits % 64))
155         {
156           nbits = ((nbits + 63) / 64) * 64;
157           tty_printf (_("rounded up to %u bits\n"), nbits);
158         }
159     }
160   else if (method == 2)
161     {
162       tty_printf ("Not yet supported; "
163                   "use the gpgsm-gencert.sh script instead\n");
164       keytype = xstrdup ("RSA"); 
165       nbits = defbits; /* We need a dummy value.  */
166     }
167   else /* method == 3 */
168     {
169       tty_printf ("Not yet supported; "
170                   "use the gpgsm-gencert.sh script instead\n");
171       keytype = xstrdup ("card:foobar");
172       nbits = defbits; /* We need a dummy value.  */
173     }
174
175   /* Ask for the key usage.  */
176   tty_printf (_("Possible actions for a %s key:\n"), "RSA");
177   tty_printf (_("   (%d) sign, encrypt\n"), 1 );
178   tty_printf (_("   (%d) sign\n"), 2 );
179   tty_printf (_("   (%d) encrypt\n"), 3 );
180   do
181     {
182       answer = tty_get (_("Your selection? "));
183       tty_kill_prompt ();
184       selection = *answer? atoi (answer): 1;
185       xfree (answer);
186       switch (selection)
187         {
188         case 1: keyusage = "sign, encrypt"; break;
189         case 2: keyusage = "sign"; break;
190         case 3: keyusage = "encrypt"; break;
191         default: keyusage = NULL; break;
192         }
193     }
194   while (!keyusage);
195
196   /* Get the subject name.  */
197   answer = NULL;
198   do
199     {
200       size_t erroff, errlen;
201
202       xfree (answer);
203       answer = tty_get (_("Enter the X.509 subject name: "));
204       tty_kill_prompt ();
205       trim_spaces (answer);
206       if (!*answer)
207         tty_printf (_("No subject name given\n"));
208       else if ( (err = ksba_dn_teststr (answer, 0, &erroff, &errlen)) )
209         {
210           if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME)
211             tty_printf (_("Invalid subject name label `%.*s'\n"),
212                         (int)errlen, answer+erroff);
213           else
214             {
215               /* TRANSLATORS: The 22 in the second string is the
216                  length of the first string up to the "%s".  Please
217                  adjust it do the length of your translation.  The
218                  second string is merely passed to atoi so you can
219                  drop everything after the number.  */
220               tty_printf (_("Invalid subject name `%s'\n"), answer);
221               tty_printf ("%*s^\n",
222                           atoi (_("22 translator: see "
223                                   "certreg-ui.c:gpgsm_gencertreq_tty"))
224                           + (int)erroff, "");
225             }
226           *answer = 0;
227         }
228     }
229   while (!*answer);
230   subject_name = answer;
231   answer = NULL;
232
233   /* Get the email addresses. */
234   tty_printf (_("Enter email addresses"));
235   tty_printf (_(" (end with an empty line):\n"));
236   ask_mb_lines (&mb_email, "Name-Email: ");
237
238   /* DNS names.  */
239   tty_printf (_("Enter DNS names"));
240   tty_printf (_(" (optional; end with an empty line):\n"));
241   ask_mb_lines (&mb_email, "Name-DNS: ");
242
243   /* URIs.  */
244   tty_printf (_("Enter URIs"));
245   tty_printf (_(" (optional; end with an empty line):\n"));
246   ask_mb_lines (&mb_email, "Name-URI: ");
247
248
249   /* Put it all together.  */
250   store_key_value_lf (&mb_result, "Key-Type: ", keytype);
251   {
252     char numbuf[30];
253     snprintf (numbuf, sizeof numbuf, "%u", nbits);
254     store_key_value_lf (&mb_result, "Key-Length: ", numbuf);
255   }
256   store_key_value_lf (&mb_result, "Key-Usage: ", keyusage);
257   store_key_value_lf (&mb_result, "Name-DN: ", subject_name);
258   if (keygrip)
259     store_key_value_lf (&mb_result, "Key-Grip: ", keygrip);
260   if (store_mb_lines (&mb_result, &mb_email))
261     goto mem_error;
262   if (store_mb_lines (&mb_result, &mb_dns))
263     goto mem_error;
264   if (store_mb_lines (&mb_result, &mb_uri))
265     goto mem_error;
266   put_membuf (&mb_result, "", 1);
267   result = get_membuf (&mb_result, NULL);
268   if (!result)
269     goto mem_error;
270
271   tty_printf (_("Parameters to be used for the certificate request:\n"));
272   for (s=result; (s2 = strchr (s, '\n')); s = s2+1, i++)
273     tty_printf ("    %.*s\n", (int)(s2-s), s);
274   tty_printf ("\n");
275
276
277   if (!tty_get_answer_is_yes ("Really create request? (y/N) "))
278      goto leave;
279
280   /* Now create a parameter file and generate the key.  */
281   fp = es_fopenmem (0, "w+");
282   if (!fp)
283     {
284       log_error (_("error creating temporary file: %s\n"), strerror (errno));
285       goto leave;
286     }
287   es_fputs (result, fp);
288   es_rewind (fp);
289   tty_printf (_("Now creating certificate request.  "
290                 "This may take a while ...\n"));
291   {
292     int save_pem = ctrl->create_pem;
293     ctrl->create_pem = 1; /* Force creation of PEM. */
294     err = gpgsm_genkey (ctrl, fp, output_fp);
295     ctrl->create_pem = save_pem;
296   }
297   if (!err)
298     tty_printf (_("Ready.  You should now send this request to your CA.\n"));
299
300
301   goto leave;
302  mem_error:
303   log_error (_("resource problem: out of core\n"));
304  leave:
305   es_fclose (fp);
306   xfree (keytype);         
307   xfree (subject_name);
308   xfree (keygrip);
309   xfree (get_membuf (&mb_email, NULL));
310   xfree (get_membuf (&mb_dns, NULL));
311   xfree (get_membuf (&mb_uri, NULL));
312   xfree (get_membuf (&mb_result, NULL));
313   xfree (result);
314 }