* certreqgen.c (read_parameters): Improved error handling.
[gnupg.git] / sm / certreqgen.c
1 /* certreqgen.c - Generate a key and a certification request
2  *      Copyright (C) 2002 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 2 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 /*
22 The format of the native parameter file is follows:
23   o Text only, line length is limited to about 1000 chars.
24   o You must use UTF-8 encoding to specify non-ascii characters.
25   o Empty lines are ignored.
26   o Leading and trailing spaces are ignored.
27   o A hash sign as the first non white space character is a comment line.
28   o Control statements are indicated by a leading percent sign, the
29     arguments are separated by white space from the keyword.
30   o Parameters are specified by a keyword, followed by a colon.  Arguments
31     are separated by white space.
32   o The first parameter must be "Key-Type", control statements
33     may be placed anywhere.
34   o Key generation takes place when either the end of the parameter file
35     is reached, the next "Key-Type" parameter is encountered or at the
36     controlstatement "%commit"
37   o Control statements:
38     %echo <text>
39         Print <text>.
40     %dry-run
41         Suppress actual key generation (useful for syntax checking).
42     %commit
43         Perform the key generation.  Note that an implicit commit is done
44         at the next "Key-Type" parameter.
45     %certfile <filename>
46         Do not write the certificate to the keyDB but to <filename>.
47         This must be given before the first
48         commit to take place, duplicate specification of the same filename
49         is ignored, the last filename before a commit is used.
50         The filename is used until a new filename is used (at commit points)
51         and all keys are written to that file.  If a new filename is given,
52         this file is created (and overwrites an existing one).
53         Both control statements must be given.
54    o The order of the parameters does not matter except for "Key-Type"
55      which must be the first parameter.  The parameters are only for the
56      generated keyblock and parameters from previous key generations are not
57      used. Some syntactically checks may be performed.
58      The currently defined parameters are:
59      Key-Type: <algo>
60         Starts a new parameter block by giving the type of the
61         primary key. The algorithm must be capable of signing.
62         This is a required parameter.  For now the only supported
63         algorithm is "rsa".
64      Key-Length: <length-in-bits>
65         Length of the key in bits.  Default is 1024.
66      Key-Usage: <usage-list>
67         Space or comma delimited list of key usage, allowed values are
68         "encrypt" and "sign".  This is used to generate the KeyUsage extension.
69         Please make sure that the algorithm is capable of this usage.  Default
70         is to allow encrypt and sign.
71      Name-DN: subject name
72         This is the DN name of the subject in rfc2253 format.
73      Name-Email: <string>
74         The ist the email address
75
76 Here is an example:
77 $ cat >foo <<EOF
78 %echo Generating a standard key
79 Key-Type: RSA
80 Key-Length: 1024
81 Name-DN: CN=test cert 1,OU=Aegypten Project,O=g10 Code GmbH,L=Düsseldorf,C=DE
82 Name-Email: joe@foo.bar
83 # Do a commit here, so that we can later print "done" :-)
84 %commit
85 %echo done
86 EOF
87 */
88
89
90 #include <config.h>
91 #include <stdio.h>
92 #include <stdlib.h>
93 #include <string.h>
94 #include <errno.h>
95 #include <unistd.h> 
96 #include <time.h>
97 #include <assert.h>
98
99 #include <gcrypt.h>
100 #include <ksba.h>
101
102 #include "gpgsm.h"
103 #include "keydb.h"
104 #include "i18n.h"
105
106
107 enum para_name {
108   pKEYTYPE,
109   pKEYLENGTH,
110   pKEYUSAGE,
111   pNAMEDN,
112   pNAMEEMAIL
113 };
114
115 struct para_data_s {
116   struct para_data_s *next;
117   int lnr;
118   enum para_name key;
119   union {
120     unsigned int usage; 
121     char value[1];
122   } u;
123 };
124
125 struct reqgen_ctrl_s {
126   int lnr;
127   int dryrun;
128   KsbaWriter writer;
129 };
130
131
132 static int proc_parameters (struct para_data_s *para,
133                             struct reqgen_ctrl_s *outctrl);
134 static int create_request (struct para_data_s *para,
135                            KsbaConstSexp public,
136                            struct reqgen_ctrl_s *outctrl);
137
138
139 \f
140 static void
141 release_parameter_list (struct para_data_s *r)
142 {
143   struct para_data_s *r2;
144   
145   for (; r ; r = r2)
146     {
147       r2 = r->next;
148       xfree(r);
149     }
150 }
151
152 static struct para_data_s *
153 get_parameter (struct para_data_s *para, enum para_name key)
154 {
155   struct para_data_s *r;
156   
157   for (r = para; r && r->key != key; r = r->next)
158     ;
159   return r;
160 }
161
162 static const char *
163 get_parameter_value (struct para_data_s *para, enum para_name key)
164 {
165   struct para_data_s *r = get_parameter (para, key);
166   return (r && *r->u.value)? r->u.value : NULL;
167 }
168
169 static int
170 get_parameter_algo (struct para_data_s *para, enum para_name key)
171 {
172   struct para_data_s *r = get_parameter (para, key);
173   if (!r)
174     return -1;
175   if (digitp (r->u.value))
176     return atoi( r->u.value );
177   return gcry_pk_map_name (r->u.value); 
178 }
179
180 /* parse the usage parameter.  Returns 0 on success.  Note that we
181    only care about sign and encrypt and don't (yet) allow all the
182    other X.509 usage to be specified; instead we will use a fixed
183    mapping to the X.509 usage flags */
184 static int
185 parse_parameter_usage (struct para_data_s *para, enum para_name key)
186 {
187   struct para_data_s *r = get_parameter (para, key);
188   char *p, *pn;
189   unsigned int use;
190   
191   if (!r)
192     return 0; /* none (this is an optional parameter)*/
193     
194   use = 0;
195   pn = r->u.value;
196   while ( (p = strsep (&pn, " \t,")) )
197     {
198       if (!*p)
199         ;
200       else if ( !ascii_strcasecmp (p, "sign") )
201         use |= GCRY_PK_USAGE_SIGN;
202       else if ( !ascii_strcasecmp (p, "encrypt") )
203         use |= GCRY_PK_USAGE_ENCR;
204       else
205         {
206           log_error ("line %d: invalid usage list\n", r->lnr);
207           return -1; /* error */
208         }
209     }
210   r->u.usage = use;
211   return 0;
212 }
213
214
215 static unsigned int
216 get_parameter_uint (struct para_data_s *para, enum para_name key)
217 {
218   struct para_data_s *r = get_parameter (para, key);
219
220   if (!r)
221     return 0;
222
223   return (unsigned int)strtoul (r->u.value, NULL, 10);
224 }
225
226
227
228 /* Read the certificate generation parameters from FP and generate
229    (all) certificate requests.  */
230 static int
231 read_parameters (FILE *fp, KsbaWriter writer)
232 {
233   static struct {
234     const char *name;
235     enum para_name key;
236   } keywords[] = {
237     { "Key-Type",       pKEYTYPE},
238     { "Key-Length",     pKEYLENGTH },
239     { "Key-Usage",      pKEYUSAGE },
240     { "Name-DN",        pNAMEDN },
241     { "Name-Email",     pNAMEEMAIL },
242     { NULL, 0 }
243   };
244   char line[1024], *p;
245   const char *err = NULL;
246   struct para_data_s *para, *r;
247   int i, rc = 0, any = 0;
248   struct reqgen_ctrl_s outctrl;
249
250   memset (&outctrl, 0, sizeof (outctrl));
251   outctrl.writer = writer;
252
253   err = NULL;
254   para = NULL;
255   while (fgets (line, DIM(line)-1, fp) )
256     {
257       char *keyword, *value;
258
259       outctrl.lnr++;
260       if (*line && line[strlen(line)-1] != '\n')
261         {
262           err = "line too long";
263           break;
264         }
265       for (p=line; spacep (p); p++)
266         ;
267       if (!*p || *p == '#')
268         continue;
269
270       keyword = p;
271       if (*keyword == '%')
272         {
273           for (; !spacep (p); p++)
274             ;
275           if (*p)
276             *p++ = 0;
277           for (; spacep (p); p++)
278             ;
279           value = p;
280           trim_trailing_spaces (value);
281
282           if (!ascii_strcasecmp (keyword, "%echo"))
283             log_info ("%s\n", value);
284           else if (!ascii_strcasecmp (keyword, "%dry-run"))
285             outctrl.dryrun = 1;
286           else if (!ascii_strcasecmp( keyword, "%commit"))
287             {
288               rc = proc_parameters (para, &outctrl);
289               if (rc)
290                 goto leave;
291               any = 1;
292               release_parameter_list (para);
293               para = NULL;
294             }
295           else
296             log_info ("skipping control `%s' (%s)\n", keyword, value);
297
298           continue;
299         }
300
301
302       if (!(p = strchr (p, ':')) || p == keyword)
303         {
304           err = "missing colon";
305           break;
306         }
307       if (*p)
308         *p++ = 0;
309       for (; spacep (p); p++)
310         ;
311       if (!*p)
312         {
313           err = "missing argument";
314           break;
315         }
316       value = p;
317       trim_trailing_spaces (value);
318
319       for (i=0; (keywords[i].name
320                  && ascii_strcasecmp (keywords[i].name, keyword)); i++)
321         ;
322       if (!keywords[i].name)
323         {
324           err = "unknown keyword";
325           break;
326         }
327       if (keywords[i].key != pKEYTYPE && !para)
328         {
329           err = "parameter block does not start with \"Key-Type\"";
330           break;
331         }
332
333       if (keywords[i].key == pKEYTYPE && para)
334         {
335           rc = proc_parameters (para, &outctrl);
336           if (rc)
337             goto leave;
338           any = 1;
339           release_parameter_list (para);
340           para = NULL;
341         }
342       else
343         {
344           for (r = para; r && r->key != keywords[i].key; r = r->next)
345             ;
346           if (r)
347             {
348               err = "duplicate keyword";
349               break;
350             }
351         }
352
353       r = xtrycalloc (1, sizeof *r + strlen( value ));
354       if (!r)
355         {
356           err = "out of core";
357           break;
358         }
359       r->lnr = outctrl.lnr;
360       r->key = keywords[i].key;
361       strcpy (r->u.value, value);
362       r->next = para;
363       para = r;
364     }
365
366   if (err)
367     {
368       log_error ("line %d: %s\n", outctrl.lnr, err);
369       rc = GNUPG_General_Error;
370     }
371   else if (ferror(fp))
372     {
373       log_error ("line %d: read error: %s\n", outctrl.lnr, strerror(errno) );
374       rc = GNUPG_General_Error;
375     }
376   else if (para)
377     {
378       rc = proc_parameters (para, &outctrl);
379       if (rc)
380         goto leave;
381       any = 1;
382     }
383
384   if (!rc && !any)
385     rc = GNUPG_No_Data;
386
387  leave:
388   release_parameter_list (para);
389   return rc;
390 }
391
392 /* check whether there are invalid characters in the email address S */
393 static int
394 has_invalid_email_chars (const char *s)
395 {
396   int at_seen=0;
397   static char valid_chars[] = "01234567890_-."
398                               "abcdefghijklmnopqrstuvwxyz"
399                               "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
400   for (; *s; s++)
401     {
402       if (*s & 0x80)
403         return 1;
404       if (*s == '@')
405         at_seen++;
406       else if (!at_seen && !( !!strchr (valid_chars, *s) || *s == '+'))
407         return 1;
408       else if (at_seen && !strchr (valid_chars, *s))
409         return 1;
410     }
411   return at_seen != 1;
412 }
413
414
415 /* Check that all required parameters are given and perform the action */
416 static int
417 proc_parameters (struct para_data_s *para, struct reqgen_ctrl_s *outctrl)
418 {
419   struct para_data_s *r;
420   const char *s;
421   int i;
422   unsigned int nbits;
423   char numbuf[20];
424   unsigned char keyparms[100];
425   int rc;
426   KsbaSexp public;
427   
428   /* check that we have all required parameters */
429   assert (get_parameter (para, pKEYTYPE));
430
431   /* We can only use RSA for now.  There is a with pkcs-10 on how to
432      use ElGamal becuase it is expected that a PK algorithm can always
433      be used for signing. */
434   i = get_parameter_algo (para, pKEYTYPE);
435   if (i < 1 || i != GCRY_PK_RSA )
436     {
437       r = get_parameter (para, pKEYTYPE);
438       log_error ("line %d: invalid algorithm\n", r->lnr);
439       return GNUPG_Invalid_Parameter;
440     }
441   
442   /* check the keylength */
443   if (!get_parameter (para, pKEYLENGTH))
444     nbits = 1024;
445   else
446     nbits = get_parameter_uint (para, pKEYLENGTH);
447   if (nbits < 512 || nbits > 4096)
448     {
449       r = get_parameter (para, pKEYTYPE);
450       log_error ("line %d: invalid key length %u (valid are 512 to 4096)\n",
451                  r->lnr, nbits);
452       return GNUPG_Invalid_Parameter;
453     }
454     
455   /* check the usage */
456   if (parse_parameter_usage (para, pKEYUSAGE))
457     return GNUPG_Invalid_Parameter;
458
459   /* check that there is a subject name and that this DN fits our
460      requirements */
461   if (!(s=get_parameter_value (para, pNAMEDN)))
462     {
463       r = get_parameter (para, pKEYTYPE);
464       log_error ("line %d: no subject name given\n", r->lnr);
465       return GNUPG_Invalid_Parameter;
466     }
467   /* fixme check s */
468
469   /* check that the optional email address is okay */
470   if ((s=get_parameter_value (para, pNAMEEMAIL)))
471     { 
472       if (has_invalid_email_chars (s)
473           || *s == '@'
474           || s[strlen(s)-1] == '@'
475           || s[strlen(s)-1] == '.'
476           || strstr(s, ".."))
477         {
478           r = get_parameter (para, pKEYTYPE);
479           log_error ("line %d: not a valid email address\n", r->lnr);
480           return GNUPG_Invalid_Parameter;
481         }
482     }
483
484   sprintf (numbuf, "%u", nbits);
485   snprintf (keyparms, DIM (keyparms)-1, 
486             "(6:genkey(3:rsa(5:nbits%d:%s)))", strlen (numbuf), numbuf);
487   rc = gpgsm_agent_genkey (keyparms, &public);
488   if (rc)
489     {
490       r = get_parameter (para, pKEYTYPE);
491       log_error ("line %d: key generation failed: %s\n",
492                  r->lnr, gnupg_strerror (rc));
493       return rc;
494     }
495
496   rc = create_request (para, public, outctrl);
497   xfree (public);
498
499   return rc;
500 }
501
502
503 /* Parameters are checked, the key pair has been created.  Now
504    generate the request and write it out */
505 static int
506 create_request (struct para_data_s *para, KsbaConstSexp public,
507                 struct reqgen_ctrl_s *outctrl)
508 {
509   KsbaCertreq cr;
510   KsbaError err;
511   GCRY_MD_HD md;
512   KsbaStopReason stopreason;
513   int rc = 0;
514   const char *s;
515
516   cr = ksba_certreq_new ();
517   if (!cr)
518     return seterr (Out_Of_Core);
519
520   md = gcry_md_open (GCRY_MD_SHA1, 0);
521   if (!md)
522     {
523       log_error ("md_open failed: %s\n", gcry_strerror (-1));
524       rc = map_gcry_err (gcry_errno ());
525       goto leave;
526     }
527   if (DBG_HASHING)
528     gcry_md_start_debug (md, "cr.cri");
529
530   ksba_certreq_set_hash_function (cr, HASH_FNC, md);
531   ksba_certreq_set_writer (cr, outctrl->writer);
532   
533   err = ksba_certreq_add_subject (cr, get_parameter_value (para, pNAMEDN));
534   if (err)
535     {
536       log_error ("error setting the subject's name: %s\n",
537                  ksba_strerror (err));
538       rc = map_ksba_err (err);
539       goto leave;
540     }
541
542   s = get_parameter_value (para, pNAMEEMAIL);
543   if (s)
544     {
545       char *buf = xtrymalloc (strlen (s) + 3);
546
547       if (!buf)
548         {
549           rc = GNUPG_Out_Of_Core;
550           goto leave;
551         }
552       *buf = '<';
553       strcpy (buf+1, s);
554       strcat (buf+1, ">");
555       err = ksba_certreq_add_subject (cr, buf);
556       xfree (buf);
557       if (err)
558         {
559           log_error ("error setting the subject's alternate name: %s\n",
560                      ksba_strerror (err));
561           rc = map_ksba_err (err);
562           goto leave;
563         }
564     }
565
566
567   err = ksba_certreq_set_public_key (cr, public);
568   if (err)
569     {
570       log_error ("error setting the public key: %s\n",
571                  ksba_strerror (err));
572       rc = map_ksba_err (err);
573       goto leave;
574     }
575                
576   do
577     {
578       err = ksba_certreq_build (cr, &stopreason);
579       if (err)
580         {
581           log_error ("ksba_certreq_build failed: %s\n", ksba_strerror (err));
582           rc = map_ksba_err (err);
583           goto leave;
584         }
585       if (stopreason == KSBA_SR_NEED_SIG)
586         {
587           GCRY_SEXP s_pkey;
588           size_t n;
589           unsigned char grip[20], hexgrip[41];
590           char *sigval;
591           size_t siglen;
592
593           n = gcry_sexp_canon_len (public, 0, NULL, NULL);
594           if (!n)
595             {
596               log_error ("libksba did not return a proper S-Exp\n");
597               err = GNUPG_Bug;
598               goto leave;
599             }
600           rc = gcry_sexp_sscan (&s_pkey, NULL, public, n);
601           if (rc)
602             {
603               log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
604               rc = map_gcry_err (rc);
605               goto leave;
606             }
607           if ( !gcry_pk_get_keygrip (s_pkey, grip) )
608             {
609               rc = seterr (General_Error);
610               log_error ("can't figure out the keygrip\n");
611               gcry_sexp_release (s_pkey);
612               goto leave;
613             }
614           gcry_sexp_release (s_pkey);
615           for (n=0; n < 20; n++)
616             sprintf (hexgrip+n*2, "%02X", grip[n]);
617
618           rc = gpgsm_agent_pksign (hexgrip,
619                                    gcry_md_read(md, GCRY_MD_SHA1), 
620                                    gcry_md_get_algo_dlen (GCRY_MD_SHA1),
621                                    GCRY_MD_SHA1,
622                                    &sigval, &siglen);
623           if (rc)
624             {
625               log_error ("signing failed: %s\n", gnupg_strerror (rc));
626               goto leave;
627             }
628           
629           err = ksba_certreq_set_sig_val (cr, sigval);
630           xfree (sigval);
631           if (err)
632             {
633               log_error ("failed to store the sig_val: %s\n",
634                          ksba_strerror (err));
635               rc = map_ksba_err (err);
636               goto leave;
637             }
638         }
639     }
640   while (stopreason != KSBA_SR_READY);   
641   
642
643  leave:
644   gcry_md_close (md);
645   ksba_certreq_release (cr);
646   return rc;  
647 }
648
649
650 \f
651 /* Create a new key by reading the parameters from in_fd.  Multiple
652    keys may be created */
653 int
654 gpgsm_genkey (CTRL ctrl, int in_fd, FILE *out_fp)
655 {
656   int rc;
657   FILE *in_fp;
658   Base64Context b64writer = NULL;
659   KsbaWriter writer;
660
661   in_fp = fdopen (dup (in_fd), "rb");
662   if (!in_fp)
663     {
664       log_error ("fdopen() failed: %s\n", strerror (errno));
665       return seterr (IO_Error);
666     }
667
668   ctrl->pem_name = "NEW CERTIFICATE REQUEST";
669   rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
670   if (rc)
671     {
672       log_error ("can't create writer: %s\n", gnupg_strerror (rc));
673       goto leave;
674     }
675
676   rc = read_parameters (in_fp, writer);
677   if (rc)
678     {
679       log_error ("error creating certificate request: %s\n",
680                  gnupg_strerror (rc));
681       goto leave;
682     }
683
684   rc = gpgsm_finish_writer (b64writer);
685   if (rc) 
686     {
687       log_error ("write failed: %s\n", gnupg_strerror (rc));
688       goto leave;
689     }
690
691   gpgsm_status (ctrl, STATUS_KEY_CREATED, "P");
692   log_info ("certificate request created\n");
693
694  leave:
695   gpgsm_destroy_writer (b64writer);
696   fclose (in_fp);
697   return rc;
698 }
699