* gpgsm.c: New option --force-crl-refresh.
[gnupg.git] / sm / certreqgen.c
index a65f3bb..a0addd2 100644 (file)
@@ -1,5 +1,5 @@
 /* certreqgen.c - Generate a key and a certification request
- *     Copyright (C) 2002 Free Software Foundation, Inc.
+ *     Copyright (C) 2002, 2003 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -96,10 +96,10 @@ EOF
 #include <time.h>
 #include <assert.h>
 
+#include "gpgsm.h"
 #include <gcrypt.h>
 #include <ksba.h>
 
-#include "gpgsm.h"
 #include "keydb.h"
 #include "i18n.h"
 
@@ -125,14 +125,14 @@ struct para_data_s {
 struct reqgen_ctrl_s {
   int lnr;
   int dryrun;
-  KsbaWriter writer;
+  ksba_writer_t writer;
 };
 
 
 static int proc_parameters (struct para_data_s *para,
                             struct reqgen_ctrl_s *outctrl);
 static int create_request (struct para_data_s *para,
-                           KsbaConstSexp public,
+                           ksba_const_sexp_t public,
                            struct reqgen_ctrl_s *outctrl);
 
 
@@ -225,10 +225,10 @@ get_parameter_uint (struct para_data_s *para, enum para_name key)
 
 
 
-/* Read the certificate generation parameters from FP and genereate
+/* Read the certificate generation parameters from FP and generate
    (all) certificate requests.  */
 static int
-read_parameters (FILE *fp, KsbaWriter writer)
+read_parameters (FILE *fp, ksba_writer_t writer)
 {
   static struct {
     const char *name;
@@ -244,7 +244,7 @@ read_parameters (FILE *fp, KsbaWriter writer)
   char line[1024], *p;
   const char *err = NULL;
   struct para_data_s *para, *r;
-  int i;
+  int i, rc = 0, any = 0;
   struct reqgen_ctrl_s outctrl;
 
   memset (&outctrl, 0, sizeof (outctrl));
@@ -270,7 +270,7 @@ read_parameters (FILE *fp, KsbaWriter writer)
       keyword = p;
       if (*keyword == '%')
         {
-          for (; !spacep (p); p++)
+          for (; *p && !spacep (p); p++)
             ;
           if (*p)
             *p++ = 0;
@@ -285,8 +285,10 @@ read_parameters (FILE *fp, KsbaWriter writer)
             outctrl.dryrun = 1;
           else if (!ascii_strcasecmp( keyword, "%commit"))
             {
-              proc_parameters (para, &outctrl);
-              /*FIXME: what about error handling */
+              rc = proc_parameters (para, &outctrl);
+              if (rc)
+                goto leave;
+              any = 1;
               release_parameter_list (para);
               para = NULL;
            }
@@ -330,7 +332,10 @@ read_parameters (FILE *fp, KsbaWriter writer)
 
       if (keywords[i].key == pKEYTYPE && para)
         {
-          proc_parameters (para, &outctrl);
+          rc = proc_parameters (para, &outctrl);
+          if (rc)
+            goto leave;
+          any = 1;
           release_parameter_list (para);
           para = NULL;
        }
@@ -359,17 +364,29 @@ read_parameters (FILE *fp, KsbaWriter writer)
     }
 
   if (err)
-    log_error ("line %d: %s\n", outctrl.lnr, err);
+    {
+      log_error ("line %d: %s\n", outctrl.lnr, err);
+      rc = gpg_error (GPG_ERR_GENERAL);
+    }
   else if (ferror(fp))
-    log_error ("line %d: read error: %s\n", outctrl.lnr, strerror(errno) );
+    {
+      log_error ("line %d: read error: %s\n", outctrl.lnr, strerror(errno) );
+      rc = gpg_error (GPG_ERR_GENERAL);
+    }
   else if (para)
     {
-      proc_parameters (para, &outctrl);
-      /*FIXME: what about error handling */
+      rc = proc_parameters (para, &outctrl);
+      if (rc)
+        goto leave;
+      any = 1;
     }
 
+  if (!rc && !any)
+    rc = gpg_error (GPG_ERR_NO_DATA);
+
+ leave:
   release_parameter_list (para);
-  return 0;
+  return rc;
 }
 
 /* check whether there are invalid characters in the email address S */
@@ -406,7 +423,7 @@ proc_parameters (struct para_data_s *para, struct reqgen_ctrl_s *outctrl)
   char numbuf[20];
   unsigned char keyparms[100];
   int rc;
-  KsbaSexp public;
+  ksba_sexp_t public;
   
   /* check that we have all required parameters */
   assert (get_parameter (para, pKEYTYPE));
@@ -419,7 +436,7 @@ proc_parameters (struct para_data_s *para, struct reqgen_ctrl_s *outctrl)
     {
       r = get_parameter (para, pKEYTYPE);
       log_error ("line %d: invalid algorithm\n", r->lnr);
-      return GNUPG_Invalid_Parameter;
+      return gpg_error (GPG_ERR_INV_PARAMETER);
     }
   
   /* check the keylength */
@@ -432,12 +449,12 @@ proc_parameters (struct para_data_s *para, struct reqgen_ctrl_s *outctrl)
       r = get_parameter (para, pKEYTYPE);
       log_error ("line %d: invalid key length %u (valid are 512 to 4096)\n",
                  r->lnr, nbits);
-      return GNUPG_Invalid_Parameter;
+      return gpg_error (GPG_ERR_INV_PARAMETER);
     }
     
   /* check the usage */
   if (parse_parameter_usage (para, pKEYUSAGE))
-    return GNUPG_Invalid_Parameter;
+    return gpg_error (GPG_ERR_INV_PARAMETER);
 
   /* check that there is a subject name and that this DN fits our
      requirements */
@@ -445,7 +462,7 @@ proc_parameters (struct para_data_s *para, struct reqgen_ctrl_s *outctrl)
     {
       r = get_parameter (para, pKEYTYPE);
       log_error ("line %d: no subject name given\n", r->lnr);
-      return GNUPG_Invalid_Parameter;
+      return gpg_error (GPG_ERR_INV_PARAMETER);
     }
   /* fixme check s */
 
@@ -460,7 +477,7 @@ proc_parameters (struct para_data_s *para, struct reqgen_ctrl_s *outctrl)
         {
           r = get_parameter (para, pKEYTYPE);
           log_error ("line %d: not a valid email address\n", r->lnr);
-          return GNUPG_Invalid_Parameter;
+          return gpg_error (GPG_ERR_INV_PARAMETER);
         }
     }
 
@@ -472,7 +489,7 @@ proc_parameters (struct para_data_s *para, struct reqgen_ctrl_s *outctrl)
     {
       r = get_parameter (para, pKEYTYPE);
       log_error ("line %d: key generation failed: %s\n",
-                 r->lnr, gnupg_strerror (rc));
+                 r->lnr, gpg_strerror (rc));
       return rc;
     }
 
@@ -486,24 +503,24 @@ proc_parameters (struct para_data_s *para, struct reqgen_ctrl_s *outctrl)
 /* Parameters are checked, the key pair has been created.  Now
    generate the request and write it out */
 static int
-create_request (struct para_data_s *para, KsbaConstSexp public,
+create_request (struct para_data_s *para, ksba_const_sexp_t public,
                 struct reqgen_ctrl_s *outctrl)
 {
-  KsbaCertreq cr;
-  KsbaError err;
-  GCRY_MD_HD md;
-  KsbaStopReason stopreason;
+  ksba_certreq_t cr;
+  gpg_error_t err;
+  gcry_md_hd_t md;
+  ksba_stop_reason_t stopreason;
   int rc = 0;
+  const char *s;
 
-  cr = ksba_certreq_new ();
-  if (!cr)
-    return seterr (Out_Of_Core);
+  err = ksba_certreq_new (&cr);
+  if (err)
+    return err;
 
-  md = gcry_md_open (GCRY_MD_SHA1, 0);
-  if (!md)
+  rc = gcry_md_open (&md, GCRY_MD_SHA1, 0);
+  if (rc)
     {
-      log_error ("md_open failed: %s\n", gcry_strerror (-1));
-      rc = map_gcry_err (gcry_errno ());
+      log_error ("md_open failed: %s\n", gpg_strerror (rc));
       goto leave;
     }
   if (DBG_HASHING)
@@ -512,21 +529,47 @@ create_request (struct para_data_s *para, KsbaConstSexp public,
   ksba_certreq_set_hash_function (cr, HASH_FNC, md);
   ksba_certreq_set_writer (cr, outctrl->writer);
   
-  err = ksba_certreq_set_subject (cr, get_parameter_value (para, pNAMEDN));
+  err = ksba_certreq_add_subject (cr, get_parameter_value (para, pNAMEDN));
   if (err)
     {
       log_error ("error setting the subject's name: %s\n",
-                 ksba_strerror (err));
-      rc = map_ksba_err (err);
+                 gpg_strerror (err));
+      rc = err;
       goto leave;
     }
 
+  s = get_parameter_value (para, pNAMEEMAIL);
+  if (s)
+    {
+      char *buf;
+
+      buf = xtrymalloc (strlen (s) + 3);
+      if (!buf)
+        {
+          rc = OUT_OF_CORE (errno);
+          goto leave;
+        }
+      *buf = '<';
+      strcpy (buf+1, s);
+      strcat (buf+1, ">");
+      err = ksba_certreq_add_subject (cr, buf);
+      xfree (buf);
+      if (err)
+        {
+          log_error ("error setting the subject's alternate name: %s\n",
+                     gpg_strerror (err));
+          rc = err;
+          goto leave;
+        }
+    }
+
+
   err = ksba_certreq_set_public_key (cr, public);
   if (err)
     {
       log_error ("error setting the public key: %s\n",
-                 ksba_strerror (err));
-      rc = map_ksba_err (err);
+                 gpg_strerror (err));
+      rc = err;
       goto leave;
     }
                
@@ -535,13 +578,13 @@ create_request (struct para_data_s *para, KsbaConstSexp public,
       err = ksba_certreq_build (cr, &stopreason);
       if (err)
         {
-          log_error ("ksba_certreq_build failed: %s\n", ksba_strerror (err));
-          rc = map_ksba_err (err);
+          log_error ("ksba_certreq_build failed: %s\n", gpg_strerror (err));
+          rc = err;
           goto leave;
         }
       if (stopreason == KSBA_SR_NEED_SIG)
         {
-          GCRY_SEXP s_pkey;
+          gcry_sexp_t s_pkey;
           size_t n;
           unsigned char grip[20], hexgrip[41];
           char *sigval;
@@ -551,19 +594,18 @@ create_request (struct para_data_s *para, KsbaConstSexp public,
           if (!n)
             {
               log_error ("libksba did not return a proper S-Exp\n");
-              err = GNUPG_Bug;
+              err = gpg_error (GPG_ERR_BUG);
               goto leave;
             }
           rc = gcry_sexp_sscan (&s_pkey, NULL, public, n);
           if (rc)
             {
-              log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
-              rc = map_gcry_err (rc);
+              log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
               goto leave;
             }
           if ( !gcry_pk_get_keygrip (s_pkey, grip) )
             {
-              rc = seterr (General_Error);
+              rc = gpg_error (GPG_ERR_GENERAL);
               log_error ("can't figure out the keygrip\n");
               gcry_sexp_release (s_pkey);
               goto leave;
@@ -572,14 +614,14 @@ create_request (struct para_data_s *para, KsbaConstSexp public,
           for (n=0; n < 20; n++)
             sprintf (hexgrip+n*2, "%02X", grip[n]);
 
-          rc = gpgsm_agent_pksign (hexgrip,
+          rc = gpgsm_agent_pksign (hexgrip, NULL,
                                    gcry_md_read(md, GCRY_MD_SHA1), 
                                    gcry_md_get_algo_dlen (GCRY_MD_SHA1),
                                    GCRY_MD_SHA1,
                                    &sigval, &siglen);
           if (rc)
             {
-              log_error ("signing failed: %s\n", gnupg_strerror (rc));
+              log_error ("signing failed: %s\n", gpg_strerror (rc));
               goto leave;
             }
           
@@ -588,8 +630,8 @@ create_request (struct para_data_s *para, KsbaConstSexp public,
           if (err)
             {
               log_error ("failed to store the sig_val: %s\n",
-                         ksba_strerror (err));
-              rc = map_ksba_err (err);
+                         gpg_strerror (err));
+              rc = err;
               goto leave;
             }
         }
@@ -613,34 +655,40 @@ gpgsm_genkey (CTRL ctrl, int in_fd, FILE *out_fp)
   int rc;
   FILE *in_fp;
   Base64Context b64writer = NULL;
-  KsbaWriter writer;
+  ksba_writer_t writer;
 
   in_fp = fdopen (dup (in_fd), "rb");
   if (!in_fp)
     {
+      gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
       log_error ("fdopen() failed: %s\n", strerror (errno));
-      return seterr (IO_Error);
+      return tmperr;
     }
 
   ctrl->pem_name = "NEW CERTIFICATE REQUEST";
   rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
   if (rc)
     {
-      log_error ("can't create writer: %s\n", gnupg_strerror (rc));
+      log_error ("can't create writer: %s\n", gpg_strerror (rc));
       goto leave;
     }
 
   rc = read_parameters (in_fp, writer);
   if (rc)
-    goto leave;
+    {
+      log_error ("error creating certificate request: %s\n",
+                 gpg_strerror (rc));
+      goto leave;
+    }
 
   rc = gpgsm_finish_writer (b64writer);
   if (rc) 
     {
-      log_error ("write failed: %s\n", gnupg_strerror (rc));
+      log_error ("write failed: %s\n", gpg_strerror (rc));
       goto leave;
     }
 
+  gpgsm_status (ctrl, STATUS_KEY_CREATED, "P");
   log_info ("certificate request created\n");
 
  leave: