* base64.c (gpgsm_create_writer): Allow to set the object name
authorWerner Koch <wk@gnupg.org>
Thu, 10 Jan 2002 19:47:20 +0000 (19:47 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 10 Jan 2002 19:47:20 +0000 (19:47 +0000)
* server.c (cmd_genkey): New.
* certreqgen.c: New.  The parameter handling code has been taken
from gnupg/g10/keygen.c version 1.0.6.
* call-agent.c (gpgsm_agent_genkey): New.

sm/ChangeLog
sm/Makefile.am
sm/base64.c
sm/call-agent.c
sm/certreqgen.c [new file with mode: 0644]
sm/encrypt.c
sm/fingerprint.c
sm/gpgsm.h
sm/keydb.c
sm/server.c
sm/sign.c

index 9474a02..d2864c7 100644 (file)
@@ -1,3 +1,21 @@
+2002-01-10  Werner Koch  <wk@gnupg.org>
+
+       * base64.c (gpgsm_create_writer): Allow to set the object name
+
+2002-01-08  Werner Koch  <wk@gnupg.org>
+
+       * keydb.c (spacep): Removed because it is now in util.c
+
+       * server.c (cmd_genkey): New.
+       * certreqgen.c: New.  The parameter handling code has been taken
+       from gnupg/g10/keygen.c version 1.0.6.
+       * call-agent.c (gpgsm_agent_genkey): New.
+
+2002-01-02  Werner Koch  <wk@gnupg.org>
+
+       * server.c (rc_to_assuan_status): Removed and changed all callers
+       to use map_to_assuan_status.
+
 2001-12-20  Werner Koch  <wk@gnupg.org>
 
        * verify.c (gpgsm_verify): Implemented non-detached signature
        * server.c (rc_to_assuan_status): New.  Use it for all commands.
 
        
- Copyright 2001 Free Software Foundation, Inc.
+ Copyright 2001, 2002 Free Software Foundation, Inc.
 
  This file is free software; as a special exception the author gives
  unlimited permission to copy and/or distribute it, with or without
index 50b8bd2..edd9566 100644 (file)
@@ -41,7 +41,8 @@ gpgsm_SOURCES = \
        sign.c \
        encrypt.c \
        decrypt.c \
-       import.c 
+       import.c \
+       certreqgen.c 
 
 
 gpgsm_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a ../kbx/libkeybox.a \
index b53009b..bf1aea1 100644 (file)
@@ -581,7 +581,8 @@ gpgsm_create_writer (Base64Context *ctx,
     {
       (*ctx)->u.wparm.fp = fp;
       if (ctrl->create_pem)
-        (*ctx)->u.wparm.pem_name = "CMS OBJECT"; /* fixme */
+        (*ctx)->u.wparm.pem_name = ctrl->pem_name? ctrl->pem_name
+                                                 : "CMS OBJECT";
       rc = ksba_writer_set_cb (w, base64_writer_cb, &(*ctx)->u.wparm);
     }
   else
index bbabe83..47a4ee7 100644 (file)
@@ -52,6 +52,12 @@ struct cipher_parm_s {
   size_t ciphertextlen;
 };
 
+struct genkey_parm_s {
+  ASSUAN_CONTEXT ctx;
+  const char *sexp;
+  size_t sexplen;
+};
+
 
 struct membuf {
   size_t len;
@@ -250,6 +256,9 @@ gpgsm_agent_pksign (const char *keygrip,
       return map_assuan_err (rc);
     }
   *r_buf = get_membuf (&data, r_buflen);
+
+  /* FIXME: check that the returned S-Exp is valid! */
+
   return *r_buf? 0 : GNUPG_Out_Of_Core;
 }
 
@@ -341,6 +350,65 @@ gpgsm_agent_pkdecrypt (const char *keygrip,
 
 
 
+\f
+/* Handle a KEYPARMS inquiry.  Note, we only send the data,
+   assuan_transact takes care of flushing and writing the end */
+static AssuanError
+inq_genkey_parms (void *opaque, const char *keyword)
+{
+  struct genkey_parm_s *parm = opaque; 
+  AssuanError rc;
+
+  rc = assuan_send_data (parm->ctx, parm->sexp, parm->sexplen);
+  return rc; 
+}
+
+
+\f
+/* Call the agent to generate a newkey */
+int
+gpgsm_agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey)
+{
+  int rc;
+  struct genkey_parm_s gk_parm;
+  struct membuf data;
+  size_t len;
+  char *buf;
+
+  *r_pubkey = NULL;
+  rc = start_agent ();
+  if (rc)
+    return rc;
+
+  rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL);
+  if (rc)
+    return map_assuan_err (rc);
+
+  init_membuf (&data, 1024);
+  gk_parm.ctx = agent_ctx;
+  gk_parm.sexp = keyparms;
+  gk_parm.sexplen = gcry_sexp_canon_len (keyparms, 0, NULL, NULL);
+  if (!gk_parm.sexplen)
+    return GNUPG_Invalid_Value;
+  rc = assuan_transact (agent_ctx, "GENKEY",
+                        membuf_data_cb, &data, 
+                        inq_genkey_parms, &gk_parm);
+  if (rc)
+    {
+      xfree (get_membuf (&data, &len));
+      return map_assuan_err (rc);
+    }
+  buf = get_membuf (&data, &len);
+  if (!buf)
+    return GNUPG_Out_Of_Core;
+  if (!gcry_sexp_canon_len (buf, len, NULL, NULL))
+    {
+      xfree (buf);
+      return GNUPG_Invalid_Sexp;
+    }
+  *r_pubkey = buf;
+  return 0;
+}
 
 
 
diff --git a/sm/certreqgen.c b/sm/certreqgen.c
new file mode 100644 (file)
index 0000000..a65f3bb
--- /dev/null
@@ -0,0 +1,651 @@
+/* certreqgen.c - Generate a key and a certification request
+ *     Copyright (C) 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/*
+The format of the native parameter file is follows:
+  o Text only, line length is limited to about 1000 chars.
+  o You must use UTF-8 encoding to specify non-ascii characters.
+  o Empty lines are ignored.
+  o Leading and trailing spaces are ignored.
+  o A hash sign as the first non white space character is a comment line.
+  o Control statements are indicated by a leading percent sign, the
+    arguments are separated by white space from the keyword.
+  o Parameters are specified by a keyword, followed by a colon.  Arguments
+    are separated by white space.
+  o The first parameter must be "Key-Type", control statements
+    may be placed anywhere.
+  o Key generation takes place when either the end of the parameter file
+    is reached, the next "Key-Type" parameter is encountered or at the
+    controlstatement "%commit"
+  o Control statements:
+    %echo <text>
+       Print <text>.
+    %dry-run
+       Suppress actual key generation (useful for syntax checking).
+    %commit
+       Perform the key generation.  Note that an implicit commit is done
+       at the next "Key-Type" parameter.
+    %certfile <filename>
+       Do not write the certificate to the keyDB but to <filename>.
+        This must be given before the first
+       commit to take place, duplicate specification of the same filename
+       is ignored, the last filename before a commit is used.
+       The filename is used until a new filename is used (at commit points)
+       and all keys are written to that file.  If a new filename is given,
+       this file is created (and overwrites an existing one).
+       Both control statements must be given.
+   o The order of the parameters does not matter except for "Key-Type"
+     which must be the first parameter.  The parameters are only for the
+     generated keyblock and parameters from previous key generations are not
+     used. Some syntactically checks may be performed.
+     The currently defined parameters are:
+     Key-Type: <algo>
+       Starts a new parameter block by giving the type of the
+       primary key. The algorithm must be capable of signing.
+       This is a required parameter.  For now the only supported
+        algorithm is "rsa".
+     Key-Length: <length-in-bits>
+       Length of the key in bits.  Default is 1024.
+     Key-Usage: <usage-list>
+        Space or comma delimited list of key usage, allowed values are
+        "encrypt" and "sign".  This is used to generate the KeyUsage extension.
+        Please make sure that the algorithm is capable of this usage.  Default
+        is to allow encrypt and sign.
+     Name-DN: subject name
+        This is the DN name of the subject in rfc2253 format.
+     Name-Email: <string>
+       The ist the email address
+
+Here is an example:
+$ cat >foo <<EOF
+%echo Generating a standard key
+Key-Type: RSA
+Key-Length: 1024
+Name-DN: CN=test cert 1,OU=Aegypten Project,O=g10 Code GmbH,L=Düsseldorf,C=DE
+Name-Email: joe@foo.bar
+# Do a commit here, so that we can later print "done" :-)
+%commit
+%echo done
+EOF
+*/
+
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h> 
+#include <time.h>
+#include <assert.h>
+
+#include <gcrypt.h>
+#include <ksba.h>
+
+#include "gpgsm.h"
+#include "keydb.h"
+#include "i18n.h"
+
+
+enum para_name {
+  pKEYTYPE,
+  pKEYLENGTH,
+  pKEYUSAGE,
+  pNAMEDN,
+  pNAMEEMAIL
+};
+
+struct para_data_s {
+  struct para_data_s *next;
+  int lnr;
+  enum para_name key;
+  union {
+    unsigned int usage; 
+    char value[1];
+  } u;
+};
+
+struct reqgen_ctrl_s {
+  int lnr;
+  int dryrun;
+  KsbaWriter 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,
+                           struct reqgen_ctrl_s *outctrl);
+
+
+\f
+static void
+release_parameter_list (struct para_data_s *r)
+{
+  struct para_data_s *r2;
+  
+  for (; r ; r = r2)
+    {
+      r2 = r->next;
+      xfree(r);
+    }
+}
+
+static struct para_data_s *
+get_parameter (struct para_data_s *para, enum para_name key)
+{
+  struct para_data_s *r;
+  
+  for (r = para; r && r->key != key; r = r->next)
+    ;
+  return r;
+}
+
+static const char *
+get_parameter_value (struct para_data_s *para, enum para_name key)
+{
+  struct para_data_s *r = get_parameter (para, key);
+  return (r && *r->u.value)? r->u.value : NULL;
+}
+
+static int
+get_parameter_algo (struct para_data_s *para, enum para_name key)
+{
+  struct para_data_s *r = get_parameter (para, key);
+  if (!r)
+    return -1;
+  if (digitp (r->u.value))
+    return atoi( r->u.value );
+  return gcry_pk_map_name (r->u.value); 
+}
+
+/* parse the usage parameter.  Returns 0 on success.  Note that we
+   only care about sign and encrypt and don't (yet) allow all the
+   other X.509 usage to be specified; instead we will use a fixed
+   mapping to the X.509 usage flags */
+static int
+parse_parameter_usage (struct para_data_s *para, enum para_name key)
+{
+  struct para_data_s *r = get_parameter (para, key);
+  char *p, *pn;
+  unsigned int use;
+  
+  if (!r)
+    return 0; /* none (this is an optional parameter)*/
+    
+  use = 0;
+  pn = r->u.value;
+  while ( (p = strsep (&pn, " \t,")) )
+    {
+      if (!*p)
+        ;
+      else if ( !ascii_strcasecmp (p, "sign") )
+        use |= GCRY_PK_USAGE_SIGN;
+      else if ( !ascii_strcasecmp (p, "encrypt") )
+        use |= GCRY_PK_USAGE_ENCR;
+      else
+        {
+          log_error ("line %d: invalid usage list\n", r->lnr);
+          return -1; /* error */
+        }
+    }
+  r->u.usage = use;
+  return 0;
+}
+
+
+static unsigned int
+get_parameter_uint (struct para_data_s *para, enum para_name key)
+{
+  struct para_data_s *r = get_parameter (para, key);
+
+  if (!r)
+    return 0;
+
+  return (unsigned int)strtoul (r->u.value, NULL, 10);
+}
+
+
+
+/* Read the certificate generation parameters from FP and genereate
+   (all) certificate requests.  */
+static int
+read_parameters (FILE *fp, KsbaWriter writer)
+{
+  static struct {
+    const char *name;
+    enum para_name key;
+  } keywords[] = {
+    { "Key-Type",       pKEYTYPE},
+    { "Key-Length",     pKEYLENGTH },
+    { "Key-Usage",      pKEYUSAGE },
+    { "Name-DN",        pNAMEDN },
+    { "Name-Email",     pNAMEEMAIL },
+    { NULL, 0 }
+  };
+  char line[1024], *p;
+  const char *err = NULL;
+  struct para_data_s *para, *r;
+  int i;
+  struct reqgen_ctrl_s outctrl;
+
+  memset (&outctrl, 0, sizeof (outctrl));
+  outctrl.writer = writer;
+
+  err = NULL;
+  para = NULL;
+  while (fgets (line, DIM(line)-1, fp) )
+    {
+      char *keyword, *value;
+
+      outctrl.lnr++;
+      if (*line && line[strlen(line)-1] != '\n')
+        {
+          err = "line too long";
+          break;
+       }
+      for (p=line; spacep (p); p++)
+        ;
+      if (!*p || *p == '#')
+        continue;
+
+      keyword = p;
+      if (*keyword == '%')
+        {
+          for (; !spacep (p); p++)
+            ;
+          if (*p)
+            *p++ = 0;
+          for (; spacep (p); p++)
+            ;
+          value = p;
+          trim_trailing_spaces (value);
+
+          if (!ascii_strcasecmp (keyword, "%echo"))
+            log_info ("%s\n", value);
+          else if (!ascii_strcasecmp (keyword, "%dry-run"))
+            outctrl.dryrun = 1;
+          else if (!ascii_strcasecmp( keyword, "%commit"))
+            {
+              proc_parameters (para, &outctrl);
+              /*FIXME: what about error handling */
+              release_parameter_list (para);
+              para = NULL;
+           }
+          else
+            log_info ("skipping control `%s' (%s)\n", keyword, value);
+
+          continue;
+       }
+
+
+      if (!(p = strchr (p, ':')) || p == keyword)
+        {
+          err = "missing colon";
+          break;
+       }
+      if (*p)
+        *p++ = 0;
+      for (; spacep (p); p++)
+        ;
+      if (!*p)
+        {
+          err = "missing argument";
+          break;
+       }
+      value = p;
+      trim_trailing_spaces (value);
+
+      for (i=0; (keywords[i].name
+                 && ascii_strcasecmp (keywords[i].name, keyword)); i++)
+        ;
+      if (!keywords[i].name)
+        {
+          err = "unknown keyword";
+          break;
+       }
+      if (keywords[i].key != pKEYTYPE && !para)
+        {
+          err = "parameter block does not start with \"Key-Type\"";
+          break;
+       }
+
+      if (keywords[i].key == pKEYTYPE && para)
+        {
+          proc_parameters (para, &outctrl);
+          release_parameter_list (para);
+          para = NULL;
+       }
+      else
+        {
+          for (r = para; r && r->key != keywords[i].key; r = r->next)
+            ;
+          if (r)
+            {
+              err = "duplicate keyword";
+              break;
+           }
+       }
+
+      r = xtrycalloc (1, sizeof *r + strlen( value ));
+      if (!r)
+        {
+          err = "out of core";
+          break;
+        }
+      r->lnr = outctrl.lnr;
+      r->key = keywords[i].key;
+      strcpy (r->u.value, value);
+      r->next = para;
+      para = r;
+    }
+
+  if (err)
+    log_error ("line %d: %s\n", outctrl.lnr, err);
+  else if (ferror(fp))
+    log_error ("line %d: read error: %s\n", outctrl.lnr, strerror(errno) );
+  else if (para)
+    {
+      proc_parameters (para, &outctrl);
+      /*FIXME: what about error handling */
+    }
+
+  release_parameter_list (para);
+  return 0;
+}
+
+/* check whether there are invalid characters in the email address S */
+static int
+has_invalid_email_chars (const char *s)
+{
+  int at_seen=0;
+  static char valid_chars[] = "01234567890_-."
+                              "abcdefghijklmnopqrstuvwxyz"
+                             "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  for (; *s; s++)
+    {
+      if (*s & 0x80)
+        return 1;
+      if (*s == '@')
+        at_seen++;
+      else if (!at_seen && !( !!strchr (valid_chars, *s) || *s == '+'))
+        return 1;
+      else if (at_seen && !strchr (valid_chars, *s))
+        return 1;
+    }
+  return at_seen != 1;
+}
+
+
+/* Check that all required parameters are given and perform the action */
+static int
+proc_parameters (struct para_data_s *para, struct reqgen_ctrl_s *outctrl)
+{
+  struct para_data_s *r;
+  const char *s;
+  int i;
+  unsigned int nbits;
+  char numbuf[20];
+  unsigned char keyparms[100];
+  int rc;
+  KsbaSexp public;
+  
+  /* check that we have all required parameters */
+  assert (get_parameter (para, pKEYTYPE));
+
+  /* We can only use RSA for now.  There is a with pkcs-10 on how to
+     use ElGamal becuase it is expected that a PK algorithm can always
+     be used for signing. */
+  i = get_parameter_algo (para, pKEYTYPE);
+  if (i < 1 || i != GCRY_PK_RSA )
+    {
+      r = get_parameter (para, pKEYTYPE);
+      log_error ("line %d: invalid algorithm\n", r->lnr);
+      return GNUPG_Invalid_Parameter;
+    }
+  
+  /* check the keylength */
+  if (!get_parameter (para, pKEYLENGTH))
+    nbits = 1024;
+  else
+    nbits = get_parameter_uint (para, pKEYLENGTH);
+  if (nbits < 512 || nbits > 4096)
+    {
+      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;
+    }
+    
+  /* check the usage */
+  if (parse_parameter_usage (para, pKEYUSAGE))
+    return GNUPG_Invalid_Parameter;
+
+  /* check that there is a subject name and that this DN fits our
+     requirements */
+  if (!(s=get_parameter_value (para, pNAMEDN)))
+    {
+      r = get_parameter (para, pKEYTYPE);
+      log_error ("line %d: no subject name given\n", r->lnr);
+      return GNUPG_Invalid_Parameter;
+    }
+  /* fixme check s */
+
+  /* check that the optional email address is okay */
+  if ((s=get_parameter_value (para, pNAMEEMAIL)))
+    { 
+      if (has_invalid_email_chars (s)
+          || *s == '@'
+          || s[strlen(s)-1] == '@'
+          || s[strlen(s)-1] == '.'
+          || strstr(s, ".."))
+        {
+          r = get_parameter (para, pKEYTYPE);
+          log_error ("line %d: not a valid email address\n", r->lnr);
+          return GNUPG_Invalid_Parameter;
+        }
+    }
+
+  sprintf (numbuf, "%u", nbits);
+  snprintf (keyparms, DIM (keyparms)-1, 
+            "(6:genkey(3:rsa(5:nbits%d:%s)))", strlen (numbuf), numbuf);
+  rc = gpgsm_agent_genkey (keyparms, &public);
+  if (rc)
+    {
+      r = get_parameter (para, pKEYTYPE);
+      log_error ("line %d: key generation failed: %s\n",
+                 r->lnr, gnupg_strerror (rc));
+      return rc;
+    }
+
+  rc = create_request (para, public, outctrl);
+  xfree (public);
+
+  return rc;
+}
+
+
+/* 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,
+                struct reqgen_ctrl_s *outctrl)
+{
+  KsbaCertreq cr;
+  KsbaError err;
+  GCRY_MD_HD md;
+  KsbaStopReason stopreason;
+  int rc = 0;
+
+  cr = ksba_certreq_new ();
+  if (!cr)
+    return seterr (Out_Of_Core);
+
+  md = gcry_md_open (GCRY_MD_SHA1, 0);
+  if (!md)
+    {
+      log_error ("md_open failed: %s\n", gcry_strerror (-1));
+      rc = map_gcry_err (gcry_errno ());
+      goto leave;
+    }
+  if (DBG_HASHING)
+    gcry_md_start_debug (md, "cr.cri");
+
+  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));
+  if (err)
+    {
+      log_error ("error setting the subject's name: %s\n",
+                 ksba_strerror (err));
+      rc = map_ksba_err (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);
+      goto leave;
+    }
+               
+  do
+    {
+      err = ksba_certreq_build (cr, &stopreason);
+      if (err)
+        {
+          log_error ("ksba_certreq_build failed: %s\n", ksba_strerror (err));
+          rc = map_ksba_err (err);
+          goto leave;
+        }
+      if (stopreason == KSBA_SR_NEED_SIG)
+        {
+          GCRY_SEXP s_pkey;
+          size_t n;
+          unsigned char grip[20], hexgrip[41];
+          char *sigval;
+          size_t siglen;
+
+          n = gcry_sexp_canon_len (public, 0, NULL, NULL);
+          if (!n)
+            {
+              log_error ("libksba did not return a proper S-Exp\n");
+              err = GNUPG_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);
+              goto leave;
+            }
+          if ( !gcry_pk_get_keygrip (s_pkey, grip) )
+            {
+              rc = seterr (General_Error);
+              log_error ("can't figure out the keygrip\n");
+              gcry_sexp_release (s_pkey);
+              goto leave;
+            }
+          gcry_sexp_release (s_pkey);
+          for (n=0; n < 20; n++)
+            sprintf (hexgrip+n*2, "%02X", grip[n]);
+
+          rc = gpgsm_agent_pksign (hexgrip,
+                                   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));
+              goto leave;
+            }
+          
+          err = ksba_certreq_set_sig_val (cr, sigval);
+          xfree (sigval);
+          if (err)
+            {
+              log_error ("failed to store the sig_val: %s\n",
+                         ksba_strerror (err));
+              rc = map_ksba_err (err);
+              goto leave;
+            }
+        }
+    }
+  while (stopreason != KSBA_SR_READY);   
+  
+
+ leave:
+  gcry_md_close (md);
+  ksba_certreq_release (cr);
+  return rc;  
+}
+
+
+\f
+/* Create a new key by reading the parameters from in_fd.  Multiple
+   keys may be created */
+int
+gpgsm_genkey (CTRL ctrl, int in_fd, FILE *out_fp)
+{
+  int rc;
+  FILE *in_fp;
+  Base64Context b64writer = NULL;
+  KsbaWriter writer;
+
+  in_fp = fdopen (dup (in_fd), "rb");
+  if (!in_fp)
+    {
+      log_error ("fdopen() failed: %s\n", strerror (errno));
+      return seterr (IO_Error);
+    }
+
+  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));
+      goto leave;
+    }
+
+  rc = read_parameters (in_fp, writer);
+  if (rc)
+    goto leave;
+
+  rc = gpgsm_finish_writer (b64writer);
+  if (rc) 
+    {
+      log_error ("write failed: %s\n", gnupg_strerror (rc));
+      goto leave;
+    }
+
+  log_info ("certificate request created\n");
+
+ leave:
+  gpgsm_destroy_writer (b64writer);
+  fclose (in_fp);
+  return rc;
+}
+
index be2a346..1ad90f8 100644 (file)
@@ -447,6 +447,7 @@ gpgsm_encrypt (CTRL ctrl, CERTLIST recplist, int data_fd, FILE *out_fp)
     }
   encparm.fp = data_fp;
 
+  ctrl->pem_name = "ENCRYPTED MESSAGE";
   rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
   if (rc)
     {
index 22ed014..a8edf6f 100644 (file)
@@ -187,3 +187,7 @@ gpgsm_get_keygrip_hexstring (KsbaCert cert)
 }
 
 
+
+
+
+
index 450b0a2..bc2b5ec 100644 (file)
@@ -98,6 +98,7 @@ struct server_control_s {
 
   int create_base64;  /* Create base64 encoded output */
   int create_pem;     /* create PEM output */
+  const char *pem_name; /* PEM name to use */
  
 };
 typedef struct server_control_s *CTRL;
@@ -175,6 +176,9 @@ int gpgsm_encrypt (CTRL ctrl, CERTLIST recplist, int in_fd, FILE *out_fp);
 /*-- decrypt.c --*/
 int gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp);
 
+/*-- certreqgen.c --*/
+int gpgsm_genkey (CTRL ctrl, int in_fd, FILE *out_fp);
+
 /*-- call-agent.c --*/
 int gpgsm_agent_pksign (const char *keygrip,
                         unsigned char *digest,
@@ -184,6 +188,7 @@ int gpgsm_agent_pksign (const char *keygrip,
 int gpgsm_agent_pkdecrypt (const char *keygrip,
                            KsbaConstSexp  ciphertext, 
                            char **r_buf, size_t *r_buflen);
+int gpgsm_agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey);
 
 
 #endif /*GPGSM_H*/
index 9a39b67..17074e8 100644 (file)
@@ -35,8 +35,6 @@
 
 #define DIRSEP_C '/'
 
-#define spacep(a) ((a) == ' ' || (a) == '\t')
-
 static int active_handles;
 
 typedef enum {
@@ -911,7 +909,7 @@ classify_user_id (const char *name,
   memset (desc, 0, sizeof *desc);
   *force_exact = 0;
   /* skip leading spaces.  Fixme: what about trailing white space? */
-  for(s = name; *s && spacep(*s); s++ )
+  for(s = name; *s && spacep (s); s++ )
     ;
 
   switch (*s) 
@@ -957,7 +955,7 @@ classify_user_id (const char *name,
 
     case '/': /* subject's DN */
       s++;
-      if (!*s || spacep (*s))
+      if (!*s || spacep (s))
         return 0; /* no DN or prefixed with a space */
       desc->u.name = s;
       mode = KEYDB_SEARCH_MODE_SUBJECT;
@@ -971,7 +969,7 @@ classify_user_id (const char *name,
         if ( *s == '/')
           { /* "#/" indicates an issuer's DN */
             s++;
-            if (!*s || spacep (*s))
+            if (!*s || spacep (s))
               return 0; /* no DN or prefixed with a space */
             desc->u.name = s;
             mode = KEYDB_SEARCH_MODE_ISSUER;
@@ -990,7 +988,7 @@ classify_user_id (const char *name,
             else
               {
                 s = si+1;
-                if (!*s || spacep (*s))
+                if (!*s || spacep (s))
                   return 0; /* no DN or prefixed with a space */
                 desc->u.name = s;
                 mode = KEYDB_SEARCH_MODE_ISSUER_SN;
@@ -1038,7 +1036,7 @@ classify_user_id (const char *name,
         }
       
       /* check if a hexadecimal number is terminated by EOS or blank */
-      if (hexlength && s[hexlength] && !spacep(s[hexlength])) 
+      if (hexlength && s[hexlength] && !spacep (s+hexlength)) 
         {
           if (hexprefix) /* a "0x" prefix without correct */
             return 0;   /* termination is an error */
index 6af69e5..9b78637 100644 (file)
@@ -1,5 +1,5 @@
 /* server.c - Server mode and main entry point 
- *     Copyright (C) 2001 Free Software Foundation, Inc.
+ *     Copyright (C) 2001, 2002 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -42,45 +42,6 @@ struct server_local_s {
   CERTLIST recplist;
 };
 
-/* Map GNUPG_xxx error codes to Assuan status codes */
-static int
-rc_to_assuan_status (int rc)
-{
-  switch (rc)
-    {
-    case 0: break;
-    case GNUPG_Bad_Certificate:   rc = ASSUAN_Bad_Certificate; break;
-    case GNUPG_Bad_Certificate_Path: rc = ASSUAN_Bad_Certificate_Path; break;
-    case GNUPG_Missing_Certificate: rc = ASSUAN_Missing_Certificate; break;
-    case GNUPG_No_Data:           rc = ASSUAN_No_Data_Available; break;
-    case GNUPG_Bad_Signature:     rc = ASSUAN_Bad_Signature; break;
-    case GNUPG_Not_Implemented:   rc = ASSUAN_Not_Implemented; break;
-    case GNUPG_No_Agent:          rc = ASSUAN_No_Agent; break;
-    case GNUPG_Agent_Error:       rc = ASSUAN_Agent_Error; break;
-    case GNUPG_No_Public_Key:     rc = ASSUAN_No_Public_Key; break;
-    case GNUPG_No_Secret_Key:     rc = ASSUAN_No_Secret_Key; break;
-    case GNUPG_Invalid_Data:      rc = ASSUAN_Invalid_Data; break;
-    case GNUPG_Invalid_Name:      rc = ASSUAN_Invalid_Name; break;
-
-    case GNUPG_Read_Error: 
-    case GNUPG_Write_Error:
-    case GNUPG_IO_Error: 
-      rc = ASSUAN_Server_IO_Error;
-      break;
-    case GNUPG_Out_Of_Core:    
-    case GNUPG_Resource_Limit: 
-      rc = ASSUAN_Server_Resource_Problem;
-      break;
-    case GNUPG_Bug: 
-    case GNUPG_Internal_Error:   
-      rc = ASSUAN_Server_Bug;
-      break;
-    default: 
-      rc = ASSUAN_Server_Fault;
-      break;
-    }
-  return rc;
-}
 
 static void 
 close_message_fd (CTRL ctrl)
@@ -155,7 +116,7 @@ cmd_recipient (ASSUAN_CONTEXT ctx, char *line)
 
   rc = gpgsm_add_to_certlist (line, &ctrl->server_local->recplist);
 
-  return rc_to_assuan_status (rc);
+  return map_to_assuan_status (rc);
 }
 
 
@@ -204,7 +165,7 @@ cmd_encrypt (ASSUAN_CONTEXT ctx, char *line)
       assuan_close_input_fd (ctx);
       assuan_close_output_fd (ctx);
     }
-  return rc_to_assuan_status (rc);
+  return map_to_assuan_status (rc);
 }
 
 /* DECRYPT
@@ -243,7 +204,7 @@ cmd_decrypt (ASSUAN_CONTEXT ctx, char *line)
       assuan_close_output_fd (ctx);
     }
 
-  return rc_to_assuan_status (rc);
+  return map_to_assuan_status (rc);
 }
 
 
@@ -288,7 +249,7 @@ cmd_verify (ASSUAN_CONTEXT ctx, char *line)
       assuan_close_output_fd (ctx);
     }
 
-  return rc_to_assuan_status (rc);
+  return map_to_assuan_status (rc);
 }
 
 
@@ -329,7 +290,7 @@ cmd_sign (ASSUAN_CONTEXT ctx, char *line)
       assuan_close_output_fd (ctx);
     }
 
-  return rc_to_assuan_status (rc);
+  return map_to_assuan_status (rc);
 }
 
 
@@ -358,7 +319,7 @@ cmd_import (ASSUAN_CONTEXT ctx, char *line)
       assuan_close_input_fd (ctx);
       assuan_close_output_fd (ctx);
     }
-  return rc_to_assuan_status (rc);
+  return map_to_assuan_status (rc);
 }
 
 /* MESSAGE FD=<n>
@@ -400,6 +361,42 @@ cmd_listkeys (ASSUAN_CONTEXT ctx, char *line)
   return 0;
 }
 
+\f
+/* GENKEY
+
+   Read the parameters in native format from the input fd and write a
+   certificate request to the output.
+ */
+static int 
+cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
+{
+  CTRL ctrl = assuan_get_pointer (ctx);
+  int inp_fd, out_fd;
+  FILE *out_fp;
+  int rc;
+
+  inp_fd = assuan_get_input_fd (ctx);
+  if (inp_fd == -1)
+    return set_error (No_Input, NULL);
+  out_fd = assuan_get_output_fd (ctx);
+  if (out_fd == -1)
+    return set_error (No_Output, NULL);
+
+  out_fp = fdopen ( dup(out_fd), "w");
+  if (!out_fp)
+    return set_error (General_Error, "fdopen() failed");
+  rc = gpgsm_genkey (ctrl, inp_fd, out_fp);
+  fclose (out_fp);
+
+  if (!rc)
+    {
+      /* close and reset the fds */
+      assuan_close_input_fd (ctx);
+      assuan_close_output_fd (ctx);
+    }
+  return map_to_assuan_status (rc);
+}
+
 
 
 
@@ -423,6 +420,7 @@ register_commands (ASSUAN_CONTEXT ctx)
     { "",     ASSUAN_CMD_OUTPUT, NULL }, 
     { "MESSAGE",    0,  cmd_message },
     { "LISTKEYS",   0,  cmd_listkeys },
+    { "GENKEY",     0,  cmd_genkey },
     { NULL }
   };
   int i, j, rc;
index b1a64ea..48ec24a 100644 (file)
--- a/sm/sign.c
+++ b/sm/sign.c
@@ -142,6 +142,7 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp)
       goto leave;
     }
 
+  ctrl->pem_name = "SIGNED MESSAGE";
   rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
   if (rc)
     {