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 + + * base64.c (gpgsm_create_writer): Allow to set the object name + +2002-01-08 Werner Koch + + * 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 + + * server.c (rc_to_assuan_status): Removed and changed all callers + to use map_to_assuan_status. + 2001-12-20 Werner Koch * 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 + Print . + %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 + Do not write the certificate to the keyDB but to . + 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: + 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 of the key in bits. Default is 1024. + Key-Usage: + 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: + The ist the email address + +Here is an example: +$ cat >foo < +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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= @@ -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) {