* certreqgen.c (create_request): Store the email address in the req.
[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 genereate
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;
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               proc_parameters (para, &outctrl);
289               /*FIXME: what about error handling */
290               release_parameter_list (para);
291               para = NULL;
292             }
293           else
294             log_info ("skipping control `%s' (%s)\n", keyword, value);
295
296           continue;
297         }
298
299
300       if (!(p = strchr (p, ':')) || p == keyword)
301         {
302           err = "missing colon";
303           break;
304         }
305       if (*p)
306         *p++ = 0;
307       for (; spacep (p); p++)
308         ;
309       if (!*p)
310         {
311           err = "missing argument";
312           break;
313         }
314       value = p;
315       trim_trailing_spaces (value);
316
317       for (i=0; (keywords[i].name
318                  && ascii_strcasecmp (keywords[i].name, keyword)); i++)
319         ;
320       if (!keywords[i].name)
321         {
322           err = "unknown keyword";
323           break;
324         }
325       if (keywords[i].key != pKEYTYPE && !para)
326         {
327           err = "parameter block does not start with \"Key-Type\"";
328           break;
329         }
330
331       if (keywords[i].key == pKEYTYPE && para)
332         {
333           proc_parameters (para, &outctrl);
334           release_parameter_list (para);
335           para = NULL;
336         }
337       else
338         {
339           for (r = para; r && r->key != keywords[i].key; r = r->next)
340             ;
341           if (r)
342             {
343               err = "duplicate keyword";
344               break;
345             }
346         }
347
348       r = xtrycalloc (1, sizeof *r + strlen( value ));
349       if (!r)
350         {
351           err = "out of core";
352           break;
353         }
354       r->lnr = outctrl.lnr;
355       r->key = keywords[i].key;
356       strcpy (r->u.value, value);
357       r->next = para;
358       para = r;
359     }
360
361   if (err)
362     log_error ("line %d: %s\n", outctrl.lnr, err);
363   else if (ferror(fp))
364     log_error ("line %d: read error: %s\n", outctrl.lnr, strerror(errno) );
365   else if (para)
366     {
367       proc_parameters (para, &outctrl);
368       /*FIXME: what about error handling */
369     }
370
371   release_parameter_list (para);
372   return 0;
373 }
374
375 /* check whether there are invalid characters in the email address S */
376 static int
377 has_invalid_email_chars (const char *s)
378 {
379   int at_seen=0;
380   static char valid_chars[] = "01234567890_-."
381                               "abcdefghijklmnopqrstuvwxyz"
382                               "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
383   for (; *s; s++)
384     {
385       if (*s & 0x80)
386         return 1;
387       if (*s == '@')
388         at_seen++;
389       else if (!at_seen && !( !!strchr (valid_chars, *s) || *s == '+'))
390         return 1;
391       else if (at_seen && !strchr (valid_chars, *s))
392         return 1;
393     }
394   return at_seen != 1;
395 }
396
397
398 /* Check that all required parameters are given and perform the action */
399 static int
400 proc_parameters (struct para_data_s *para, struct reqgen_ctrl_s *outctrl)
401 {
402   struct para_data_s *r;
403   const char *s;
404   int i;
405   unsigned int nbits;
406   char numbuf[20];
407   unsigned char keyparms[100];
408   int rc;
409   KsbaSexp public;
410   
411   /* check that we have all required parameters */
412   assert (get_parameter (para, pKEYTYPE));
413
414   /* We can only use RSA for now.  There is a with pkcs-10 on how to
415      use ElGamal becuase it is expected that a PK algorithm can always
416      be used for signing. */
417   i = get_parameter_algo (para, pKEYTYPE);
418   if (i < 1 || i != GCRY_PK_RSA )
419     {
420       r = get_parameter (para, pKEYTYPE);
421       log_error ("line %d: invalid algorithm\n", r->lnr);
422       return GNUPG_Invalid_Parameter;
423     }
424   
425   /* check the keylength */
426   if (!get_parameter (para, pKEYLENGTH))
427     nbits = 1024;
428   else
429     nbits = get_parameter_uint (para, pKEYLENGTH);
430   if (nbits < 512 || nbits > 4096)
431     {
432       r = get_parameter (para, pKEYTYPE);
433       log_error ("line %d: invalid key length %u (valid are 512 to 4096)\n",
434                  r->lnr, nbits);
435       return GNUPG_Invalid_Parameter;
436     }
437     
438   /* check the usage */
439   if (parse_parameter_usage (para, pKEYUSAGE))
440     return GNUPG_Invalid_Parameter;
441
442   /* check that there is a subject name and that this DN fits our
443      requirements */
444   if (!(s=get_parameter_value (para, pNAMEDN)))
445     {
446       r = get_parameter (para, pKEYTYPE);
447       log_error ("line %d: no subject name given\n", r->lnr);
448       return GNUPG_Invalid_Parameter;
449     }
450   /* fixme check s */
451
452   /* check that the optional email address is okay */
453   if ((s=get_parameter_value (para, pNAMEEMAIL)))
454     { 
455       if (has_invalid_email_chars (s)
456           || *s == '@'
457           || s[strlen(s)-1] == '@'
458           || s[strlen(s)-1] == '.'
459           || strstr(s, ".."))
460         {
461           r = get_parameter (para, pKEYTYPE);
462           log_error ("line %d: not a valid email address\n", r->lnr);
463           return GNUPG_Invalid_Parameter;
464         }
465     }
466
467   sprintf (numbuf, "%u", nbits);
468   snprintf (keyparms, DIM (keyparms)-1, 
469             "(6:genkey(3:rsa(5:nbits%d:%s)))", strlen (numbuf), numbuf);
470   rc = gpgsm_agent_genkey (keyparms, &public);
471   if (rc)
472     {
473       r = get_parameter (para, pKEYTYPE);
474       log_error ("line %d: key generation failed: %s\n",
475                  r->lnr, gnupg_strerror (rc));
476       return rc;
477     }
478
479   rc = create_request (para, public, outctrl);
480   xfree (public);
481
482   return rc;
483 }
484
485
486 /* Parameters are checked, the key pair has been created.  Now
487    generate the request and write it out */
488 static int
489 create_request (struct para_data_s *para, KsbaConstSexp public,
490                 struct reqgen_ctrl_s *outctrl)
491 {
492   KsbaCertreq cr;
493   KsbaError err;
494   GCRY_MD_HD md;
495   KsbaStopReason stopreason;
496   int rc = 0;
497   const char *s;
498
499   cr = ksba_certreq_new ();
500   if (!cr)
501     return seterr (Out_Of_Core);
502
503   md = gcry_md_open (GCRY_MD_SHA1, 0);
504   if (!md)
505     {
506       log_error ("md_open failed: %s\n", gcry_strerror (-1));
507       rc = map_gcry_err (gcry_errno ());
508       goto leave;
509     }
510   if (DBG_HASHING)
511     gcry_md_start_debug (md, "cr.cri");
512
513   ksba_certreq_set_hash_function (cr, HASH_FNC, md);
514   ksba_certreq_set_writer (cr, outctrl->writer);
515   
516   err = ksba_certreq_add_subject (cr, get_parameter_value (para, pNAMEDN));
517   if (err)
518     {
519       log_error ("error setting the subject's name: %s\n",
520                  ksba_strerror (err));
521       rc = map_ksba_err (err);
522       goto leave;
523     }
524
525   s = get_parameter_value (para, pNAMEEMAIL);
526   if (s)
527     {
528       char *buf = xtrymalloc (strlen (s) + 3);
529
530       if (!buf)
531         {
532           rc = GNUPG_Out_Of_Core;
533           goto leave;
534         }
535       *buf = '<';
536       strcpy (buf+1, s);
537       strcat (buf+1, ">");
538       err = ksba_certreq_add_subject (cr, buf);
539       xfree (buf);
540       if (err)
541         {
542           log_error ("error setting the subject's alternate name: %s\n",
543                      ksba_strerror (err));
544           rc = map_ksba_err (err);
545           goto leave;
546         }
547     }
548
549
550   err = ksba_certreq_set_public_key (cr, public);
551   if (err)
552     {
553       log_error ("error setting the public key: %s\n",
554                  ksba_strerror (err));
555       rc = map_ksba_err (err);
556       goto leave;
557     }
558                
559   do
560     {
561       err = ksba_certreq_build (cr, &stopreason);
562       if (err)
563         {
564           log_error ("ksba_certreq_build failed: %s\n", ksba_strerror (err));
565           rc = map_ksba_err (err);
566           goto leave;
567         }
568       if (stopreason == KSBA_SR_NEED_SIG)
569         {
570           GCRY_SEXP s_pkey;
571           size_t n;
572           unsigned char grip[20], hexgrip[41];
573           char *sigval;
574           size_t siglen;
575
576           n = gcry_sexp_canon_len (public, 0, NULL, NULL);
577           if (!n)
578             {
579               log_error ("libksba did not return a proper S-Exp\n");
580               err = GNUPG_Bug;
581               goto leave;
582             }
583           rc = gcry_sexp_sscan (&s_pkey, NULL, public, n);
584           if (rc)
585             {
586               log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
587               rc = map_gcry_err (rc);
588               goto leave;
589             }
590           if ( !gcry_pk_get_keygrip (s_pkey, grip) )
591             {
592               rc = seterr (General_Error);
593               log_error ("can't figure out the keygrip\n");
594               gcry_sexp_release (s_pkey);
595               goto leave;
596             }
597           gcry_sexp_release (s_pkey);
598           for (n=0; n < 20; n++)
599             sprintf (hexgrip+n*2, "%02X", grip[n]);
600
601           rc = gpgsm_agent_pksign (hexgrip,
602                                    gcry_md_read(md, GCRY_MD_SHA1), 
603                                    gcry_md_get_algo_dlen (GCRY_MD_SHA1),
604                                    GCRY_MD_SHA1,
605                                    &sigval, &siglen);
606           if (rc)
607             {
608               log_error ("signing failed: %s\n", gnupg_strerror (rc));
609               goto leave;
610             }
611           
612           err = ksba_certreq_set_sig_val (cr, sigval);
613           xfree (sigval);
614           if (err)
615             {
616               log_error ("failed to store the sig_val: %s\n",
617                          ksba_strerror (err));
618               rc = map_ksba_err (err);
619               goto leave;
620             }
621         }
622     }
623   while (stopreason != KSBA_SR_READY);   
624   
625
626  leave:
627   gcry_md_close (md);
628   ksba_certreq_release (cr);
629   return rc;  
630 }
631
632
633 \f
634 /* Create a new key by reading the parameters from in_fd.  Multiple
635    keys may be created */
636 int
637 gpgsm_genkey (CTRL ctrl, int in_fd, FILE *out_fp)
638 {
639   int rc;
640   FILE *in_fp;
641   Base64Context b64writer = NULL;
642   KsbaWriter writer;
643
644   in_fp = fdopen (dup (in_fd), "rb");
645   if (!in_fp)
646     {
647       log_error ("fdopen() failed: %s\n", strerror (errno));
648       return seterr (IO_Error);
649     }
650
651   ctrl->pem_name = "NEW CERTIFICATE REQUEST";
652   rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
653   if (rc)
654     {
655       log_error ("can't create writer: %s\n", gnupg_strerror (rc));
656       goto leave;
657     }
658
659   rc = read_parameters (in_fp, writer);
660   if (rc)
661     goto leave;
662
663   rc = gpgsm_finish_writer (b64writer);
664   if (rc) 
665     {
666       log_error ("write failed: %s\n", gnupg_strerror (rc));
667       goto leave;
668     }
669
670   log_info ("certificate request created\n");
671
672  leave:
673   gpgsm_destroy_writer (b64writer);
674   fclose (in_fp);
675   return rc;
676 }
677