summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2002-01-10 20:47:20 +0100
committerWerner Koch <wk@gnupg.org>2002-01-10 20:47:20 +0100
commitdc37fe184907dfb70a99b573b8e36fa71d36061f (patch)
tree40860a3645374c3dcd0ef07edb84471e39045b53
parent*** empty log message *** (diff)
downloadgnupg2-dc37fe184907dfb70a99b573b8e36fa71d36061f.tar.xz
gnupg2-dc37fe184907dfb70a99b573b8e36fa71d36061f.zip
* base64.c (gpgsm_create_writer): Allow to set the object name
* 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.
-rw-r--r--sm/ChangeLog20
-rw-r--r--sm/Makefile.am3
-rw-r--r--sm/base64.c3
-rw-r--r--sm/call-agent.c68
-rw-r--r--sm/certreqgen.c651
-rw-r--r--sm/encrypt.c1
-rw-r--r--sm/fingerprint.c4
-rw-r--r--sm/gpgsm.h5
-rw-r--r--sm/keydb.c12
-rw-r--r--sm/server.c90
-rw-r--r--sm/sign.c1
11 files changed, 802 insertions, 56 deletions
diff --git a/sm/ChangeLog b/sm/ChangeLog
index 9474a02a5..d2864c77b 100644
--- a/sm/ChangeLog
+++ b/sm/ChangeLog
@@ -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
@@ -126,7 +144,7 @@
* 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
diff --git a/sm/Makefile.am b/sm/Makefile.am
index 50b8bd268..edd956693 100644
--- a/sm/Makefile.am
+++ b/sm/Makefile.am
@@ -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 \
diff --git a/sm/base64.c b/sm/base64.c
index b53009b85..bf1aea179 100644
--- a/sm/base64.c
+++ b/sm/base64.c
@@ -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
diff --git a/sm/call-agent.c b/sm/call-agent.c
index bbabe8352..47a4ee710 100644
--- a/sm/call-agent.c
+++ b/sm/call-agent.c
@@ -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,
+
+/* 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;
+}
+
+
+
+/* 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
index 000000000..a65f3bbf7
--- /dev/null
+++ b/sm/certreqgen.c
@@ -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);
+
+
+
+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;
+}
+
+
+
+/* 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;
+}
+
diff --git a/sm/encrypt.c b/sm/encrypt.c
index be2a346ae..1ad90f8dd 100644
--- a/sm/encrypt.c
+++ b/sm/encrypt.c
@@ -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)
{
diff --git a/sm/fingerprint.c b/sm/fingerprint.c
index 22ed0149d..a8edf6f5a 100644
--- a/sm/fingerprint.c
+++ b/sm/fingerprint.c
@@ -187,3 +187,7 @@ gpgsm_get_keygrip_hexstring (KsbaCert cert)
}
+
+
+
+
diff --git a/sm/gpgsm.h b/sm/gpgsm.h
index 450b0a291..bc2b5ec44 100644
--- a/sm/gpgsm.h
+++ b/sm/gpgsm.h
@@ -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*/
diff --git a/sm/keydb.c b/sm/keydb.c
index 9a39b67fb..17074e800 100644
--- a/sm/keydb.c
+++ b/sm/keydb.c
@@ -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 */
diff --git a/sm/server.c b/sm/server.c
index 6af69e5f4..9b78637be 100644
--- a/sm/server.c
+++ b/sm/server.c
@@ -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;
}
+
+/* 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;
diff --git a/sm/sign.c b/sm/sign.c
index b1a64ea3c..48ec24a4d 100644
--- 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)
{