diff --git a/sm/ChangeLog b/sm/ChangeLog index f0d7c2fe2..9ca988635 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,9 @@ +2001-11-27 Werner Koch + + * base64.c: New. Changed all other functions to use this instead + of direct creation of ksba_reader/writer. + * gpgsm.c (main): Set ctrl.auto_encoding unless --no-armor is used. + 2001-11-26 Werner Koch * gpgsm.c: New option --agent-program diff --git a/sm/Makefile.am b/sm/Makefile.am index c6aecdb5b..fbfe31af4 100644 --- a/sm/Makefile.am +++ b/sm/Makefile.am @@ -31,12 +31,14 @@ gpgsm_SOURCES = \ server.c \ call-agent.c \ fingerprint.c \ + base64.c \ certdump.c \ certcheck.c \ certpath.c \ keylist.c \ verify.c \ sign.c \ + encrypt.c \ import.c diff --git a/sm/base64.c b/sm/base64.c new file mode 100644 index 000000000..f60015dd7 --- /dev/null +++ b/sm/base64.c @@ -0,0 +1,401 @@ +/* base64.c + * Copyright (C) 2001 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "gpgsm.h" +#include "i18n.h" + + +/* data used by the reader callbacks */ +struct reader_cb_parm_s { + FILE *fp; + unsigned char line[1024]; + int linelen; + int readpos; + int have_lf; + unsigned long line_counter; + + int autodetect; /* try to detect the input encoding */ + int assume_pem; /* assume input encoding is PEM */ + int assume_base64; /* assume inpout is base64 encoded */ + + int identified; + int is_pem; + int stop_seen; + + struct { + int idx; + unsigned char val; + int stop_seen; + } base64; +}; + + +struct base64_context_s { + struct reader_cb_parm_s rparm; +}; + + +/* The base-64 character list */ +static unsigned char bintoasc[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; +/* The reverse base-64 list */ +static unsigned char asctobin[256] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff +}; + + + +static int +base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread) +{ + struct reader_cb_parm_s *parm = cb_value; + size_t n; + int c, c2; + + *nread = 0; + if (!buffer) + return -1; /* not supported */ + + next: + if (!parm->linelen) + { + /* read an entire line or up to the size of the buffer */ + parm->line_counter++; + parm->have_lf = 0; + for (n=0; n < DIM(parm->line);) + { + c = getc (parm->fp); + if (c == EOF) + { + if (ferror (parm->fp)) + return -1; + break; + } + parm->line[n++] = c; + if (c == '\n') + { + parm->have_lf = 1; + /* FIXME: we need to skip overlong lines while detecting + the dashed lines */ + break; + } + } + parm->linelen = n; + if (!n) + return -1; /* eof */ + parm->readpos = 0; + } + + if (!parm->identified) + { + if (parm->line_counter == 1 && !parm->have_lf) + { + /* first line too long - assume DER encoding */ + parm->is_pem = 0; + } + else if (parm->line_counter == 1 && parm->linelen && *parm->line == 0x30) + { + /* the very first bytes does pretty much look like a SEQUENCE tag*/ + parm->is_pem = 0; + } + else if ( parm->have_lf && !strncmp (parm->line, "-----BEGIN ", 11) + && strncmp (parm->line+11, "PGP ", 4) ) + { + /* Fixme: we must only compare if the line really starts at + the beginning */ + parm->is_pem = 1; + parm->linelen = parm->readpos = 0; + } + else + { + parm->linelen = parm->readpos = 0; + goto next; + } + parm->identified = 1; + parm->base64.stop_seen = 0; + parm->base64.idx = 0; + } + + + n = 0; + if (parm->is_pem) + { + if (parm->have_lf && !strncmp (parm->line, "-----END ", 9)) + { + parm->identified = 0; + parm->linelen = parm->readpos = 0; + /* let us return 0 */ + } + else if (parm->stop_seen) + { /* skip the rest of the line */ + parm->linelen = parm->readpos = 0; + } + else + { + int idx = parm->base64.idx; + unsigned char val = parm->base64.val; + + while (n < count && parm->readpos < parm->linelen ) + { + c = parm->line[parm->readpos++]; + if (c == '\n' || c == ' ' || c == '\r' || c == '\t') + continue; + if (c == '=') + { /* pad character: stop */ + if (idx == 1) + buffer[n++] = val; + parm->stop_seen = 1; + break; + } + if( (c = asctobin[(c2=c)]) == 255 ) + { + log_error (_("invalid radix64 character %02x skipped\n"), + c2); + continue; + } + switch (idx) + { + case 0: + val = c << 2; + break; + case 1: + val |= (c>>4)&3; + buffer[n++] = val; + val = (c<<4)&0xf0; + break; + case 2: + val |= (c>>2)&15; + buffer[n++] = val; + val = (c<<6)&0xc0; + break; + case 3: + val |= c&0x3f; + buffer[n++] = val; + break; + } + idx = (idx+1) % 4; + } + if (parm->readpos == parm->linelen) + parm->linelen = parm->readpos = 0; + + parm->base64.idx = idx; + parm->base64.val = val; + } + } + else + { /* DER encoded */ + while (n < count && parm->readpos < parm->linelen) + buffer[n++] = parm->line[parm->readpos++]; + if (parm->readpos == parm->linelen) + parm->linelen = parm->readpos = 0; + } + + *nread = n; + return 0; +} + + + +static int +simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread) +{ + struct reader_cb_parm_s *parm = cb_value; + size_t n; + int c = 0; + + *nread = 0; + if (!buffer) + return -1; /* not supported */ + + for (n=0; n < count; n++) + { + c = getc (parm->fp); + if (c == EOF) + { + if ( ferror (parm->fp) ) + return -1; + if (n) + break; /* return what we have before an EOF */ + return -1; + } + *(byte *)buffer++ = c; + } + + *nread = n; + return 0; +} + + + + + +/* Create a reader for the given file descriptor. Depending on the + control information an input decoding is automagically choosen. + The function returns a Base64Context object which must be passed to + the gpgme_destroy_reader function. The created KsbaReader object + is also returned, but the caller must not call the + ksba_reader_release function on. */ +int +gpgsm_create_reader (Base64Context *ctx, + CTRL ctrl, FILE *fp, KsbaReader *r_reader) +{ + int rc; + KsbaReader r; + + *r_reader = NULL; + *ctx = xtrycalloc (1, sizeof **ctx); + if (!*ctx) + return seterr (Out_Of_Core); + + r = ksba_reader_new (); + if (!r) + { + xfree (*ctx); *ctx = NULL; + return seterr (Out_Of_Core); + } + + (*ctx)->rparm.fp = fp; + if (ctrl->is_pem) + { + (*ctx)->rparm.assume_pem = 1; + (*ctx)->rparm.assume_base64 = 1; + rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->rparm); + } + else if (ctrl->is_base64) + { + (*ctx)->rparm.assume_base64 = 1; + rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->rparm); + } + else if (ctrl->autodetect_encoding) + { + (*ctx)->rparm.autodetect = 1; + rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->rparm); + } + else + rc = ksba_reader_set_cb (r, simple_reader_cb, &(*ctx)->rparm); + + if (rc) + { + ksba_reader_release (r); + xfree (*ctx); *ctx = NULL; + return map_ksba_err (rc); + } + + *r_reader = r; + return 0; +} + + +void +gpgsm_destroy_reader (Base64Context ctx) +{ + xfree (ctx); +} + + + +/* Create a writer for the given stream. Depending on the control + information an output encoding is automagically choosen. The + function returns a Base64Context object which must be passed to the + gpgme_destroy_writer function. The created KsbaWriter object is + also returned, but the caller must not call the ksba_reader_release + function on. */ +int +gpgsm_create_writer (Base64Context *ctx, + CTRL ctrl, FILE *fp, KsbaWriter *r_writer) +{ + int rc; + KsbaWriter w; + + *r_writer = NULL; + *ctx = xtrycalloc (1, sizeof **ctx); + if (!*ctx) + return seterr (Out_Of_Core); + + w = ksba_writer_new (); + if (!w) + { + xfree (*ctx); *ctx = NULL; + return seterr (Out_Of_Core); + } + + if (ctrl->create_pem || ctrl->create_base64) + { + return seterr (Not_Implemented); + } + else + rc = ksba_writer_set_file (w, fp); + + if (rc) + { + ksba_writer_release (w); + xfree (*ctx); *ctx = NULL; + return map_ksba_err (rc); + } + + *r_writer = w; + return 0; +} + + +void +gpgsm_destroy_writer (Base64Context ctx) +{ + xfree (ctx); +} + + + + + diff --git a/sm/encrypt.c b/sm/encrypt.c new file mode 100644 index 000000000..2b30463bb --- /dev/null +++ b/sm/encrypt.c @@ -0,0 +1,256 @@ +/* encrypt.c - Encrypt a message + * Copyright (C) 2001 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "gpgsm.h" +#include "keydb.h" +#include "i18n.h" + + +KsbaCert +get_default_recipient (void) +{ + return NULL; +} + + + +/* Perform an encrypt operation. + + Encrypt the data received on DATA-FD and write it to OUT_FP. The + recipients are hardwired for now. */ +int +gpgsm_encrypt (CTRL ctrl, int data_fd, FILE *out_fp) +{ + int i, rc; + Base64Context b64reader = NULL; + Base64Context b64writer = NULL; + KsbaError err; + KsbaWriter writer; + KsbaReader reader; + KsbaCMS cms = NULL; + KsbaStopReason stopreason; + KsbaCert cert; + KEYDB_HANDLE kh = NULL; + GCRY_MD_HD data_md = NULL; + int signer; + const char *algoid; + FILE *data_fp = NULL; + int algo; + + + kh = keydb_new (0); + if (!kh) + { + log_error (_("failed to allocated keyDB handle\n")); + rc = GNUPG_General_Error; + goto leave; + } + + data_fp = fdopen ( dup (data_fd), "rb"); + if (!data_fp) + { + log_error ("fdopen() failed: %s\n", strerror (errno)); + rc = seterr (IO_Error); + goto leave; + } + + rc = gpgsm_create_reader (&b64reader, ctrl, data_fp, &reader); + if (rc) + { + log_error ("can't create reader: %s\n", gnupg_strerror (rc)); + goto leave; + } + + rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer); + if (rc) + { + log_error ("can't create writer: %s\n", gnupg_strerror (rc)); + goto leave; + } + + cms = ksba_cms_new (); + if (!cms) + { + rc = seterr (Out_Of_Core); + goto leave; + } + + err = ksba_cms_set_reader_writer (cms, reader, writer); + if (err) + { + log_debug ("ksba_cms_set_reader_writer failed: %s\n", + ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } + + /* We are going to create signed data with data as encap. content */ + err = ksba_cms_set_content_type (cms, 0, KSBA_CT_ENVELOPED_DATA); + if (!err) + err = ksba_cms_set_content_type (cms, 1, KSBA_CT_ENCRYPTED_DATA); + if (err) + { + log_debug ("ksba_cms_set_content_type failed: %s\n", + ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } + + + /* gather certificates of recipients and store them in the CMS object */ + cert = get_default_recipient (); + if (!cert) + { + log_error ("no default recipient found\n"); + rc = seterr (General_Error); + goto leave; + } +/* err = ksba_cms_add_signer (cms, cert); */ +/* if (err) */ +/* { */ +/* log_debug ("ksba_cms_add_signer failed: %s\n", ksba_strerror (err)); */ +/* rc = map_ksba_err (err); */ +/* goto leave; */ +/* } */ + cert = NULL; /* cms does now own the certificate */ + + /* Set the hash algorithm we are going to use */ + err = ksba_cms_add_digest_algo (cms, "1.3.14.3.2.26" /*SHA-1*/); + if (err) + { + log_debug ("ksba_cms_add_digest_algo failed: %s\n", ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } + + /* Prepare hashing (actually we are figuring out what we have set above)*/ + data_md = gcry_md_open (0, 0); + if (!data_md) + { + rc = map_gcry_err (gcry_errno()); + log_error ("md_open failed: %s\n", gcry_strerror (-1)); + goto leave; + } + for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++) + { + algo = gcry_md_map_name (algoid); + if (!algo) + { + log_error ("unknown hash algorithm `%s'\n", algoid? algoid:"?"); + rc = GNUPG_Bug; + goto leave; + } + gcry_md_enable (data_md, algo); + } + + signer = 0; + do + { + err = ksba_cms_build (cms, &stopreason); + if (err) + { + log_debug ("ksba_cms_build failed: %s\n", ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } + log_debug ("ksba_cms_build - stop reason %d\n", stopreason); + + if (stopreason == KSBA_SR_BEGIN_DATA) + { + } + else if (stopreason == KSBA_SR_NEED_SIG) + { /* calculate the signature for all signers */ + GCRY_MD_HD md; + + algo = GCRY_MD_SHA1; + signer = 0; + md = gcry_md_open (algo, 0); + if (!md) + { + log_error ("md_open failed: %s\n", gcry_strerror (-1)); + goto leave; + } + ksba_cms_set_hash_function (cms, HASH_FNC, md); + rc = ksba_cms_hash_signed_attrs (cms, signer); + if (rc) + { + log_debug ("hashing signed attrs failed: %s\n", + ksba_strerror (rc)); + gcry_md_close (md); + goto leave; + } + + { /* This is all an temporary hack */ + char *sigval; + + cert = NULL; + if (!cert) + { + log_error ("oops - failed to get cert again\n"); + rc = seterr (General_Error); + goto leave; + } + + sigval = NULL; + rc = gpgsm_create_cms_signature (cert, md, algo, &sigval); + if (rc) + { + ksba_cert_release (cert); + goto leave; + } + + err = ksba_cms_set_sig_val (cms, signer, sigval); + xfree (sigval); + if (err) + { + log_error ("failed to store the signature: %s\n", + ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } + } + } + } + while (stopreason != KSBA_SR_READY); + + log_info ("signature created\n"); + + leave: + ksba_cms_release (cms); + gpgsm_destroy_writer (b64writer); + gpgsm_destroy_reader (b64reader); + keydb_release (kh); + gcry_md_close (data_md); + if (data_fp) + fclose (data_fp); + return rc; +} diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 0b6b7c237..f6cf4aeef 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -591,6 +591,7 @@ main ( int argc, char **argv) memset (&ctrl, 0, sizeof ctrl); ctrl.no_server = 1; ctrl.status_fd = -1; /* not status output */ + ctrl.autodetect_encoding = 1; /* set the default option file */ if (default_config ) @@ -661,7 +662,10 @@ main ( int argc, char **argv) case aVerify: set_cmd (&cmd, aVerify); break; case oArmor: opt.armor = 1; opt.no_armor=0; break; - case oNoArmor: opt.no_armor=1; opt.armor=0; break; + case oNoArmor: + ctrl.autodetect_encoding = 0; + opt.no_armor=1; opt.armor=0; + break; case oOutput: opt.outfile = pargs.r.ret_str; break; case oQuiet: opt.quiet = 1; break; case oNoTTY: /* fixme:tty_no_terminal(1);*/ break; diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 00ae32e00..916a2cd38 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -45,7 +45,7 @@ struct { int fingerprint; /* list fingerprints in all key listings */ - int armor; /* force base64 armoring */ + int armor; /* force base64 armoring (see also ctrl.with_base64) */ int no_armor; /* don't try to figure out whether data is base64 armored*/ int def_cipher_algo; /* cipher algorithm to use if nothing else is know */ @@ -89,9 +89,20 @@ struct server_control_s { int status_fd; /* only for non-server mode */ struct server_local_s *server_local; int with_colons; /* use column delimited output format */ + + int autodetect_encoding; /* try to detect the input encoding */ + int is_pem; /* Is in PEM format */ + int is_base64; /* is in plain base-64 format */ + + int create_base64; /* Create base64 encoded output */ + int create_pem; /* create PEM output */ + }; typedef struct server_control_s *CTRL; +/* data structure osed in base64.c */ +typedef struct base64_context_s *Base64Context; + /*-- gpgsm.c --*/ void gpgsm_exit (int rc); @@ -107,6 +118,14 @@ char *gpgsm_get_fingerprint_hexstring (KsbaCert cert, int algo); char *gpgsm_get_keygrip (KsbaCert cert, char *array); char *gpgsm_get_keygrip_hexstring (KsbaCert cert); +/*-- base64.c --*/ +int gpgsm_create_reader (Base64Context *ctx, + CTRL ctrl, FILE *fp, KsbaReader *r_reader); +void gpgsm_destroy_reader (Base64Context ctx); +int gpgsm_create_writer (Base64Context *ctx, + CTRL ctrl, FILE *fp, KsbaWriter *r_writer); +void gpgsm_destroy_writer (Base64Context ctx); + /*-- certdump.c --*/ void gpgsm_dump_cert (const char *text, KsbaCert cert); diff --git a/sm/import.c b/sm/import.c index fc628a6f1..0e9618ca8 100644 --- a/sm/import.c +++ b/sm/import.c @@ -34,208 +34,6 @@ #include "keydb.h" #include "i18n.h" -struct reader_cb_parm_s { - FILE *fp; - unsigned char line[1024]; - int linelen; - int readpos; - int have_lf; - unsigned long line_counter; - - int identified; - int is_pem; - int stop_seen; - - struct { - int idx; - unsigned char val; - int stop_seen; - } base64; - - -}; - -/* static unsigned char bintoasc[] = */ -/* "ABCDEFGHIJKLMNOPQRSTUVWXYZ" */ -/* "abcdefghijklmnopqrstuvwxyz" */ -/* "0123456789+/"; */ - -static unsigned char asctobin[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, - 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, - 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff -}; - - - -static int -reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread) -{ - struct reader_cb_parm_s *parm = cb_value; - size_t n; - int c, c2; - - *nread = 0; - if (!buffer) - return -1; /* not supported */ - - next: - if (!parm->linelen) - { - /* read an entire line or up to the size of the buffer */ - parm->line_counter++; - parm->have_lf = 0; - for (n=0; n < DIM(parm->line);) - { - c = getc (parm->fp); - if (c == EOF) - { - if (ferror (parm->fp)) - return -1; - break; - } - parm->line[n++] = c; - if (c == '\n') - { - parm->have_lf = 1; - /* FIXME: we need to skip overlong lines while detecting - the dashed lines */ - break; - } - } - parm->linelen = n; - if (!n) - return -1; /* eof */ - parm->readpos = 0; - } - - if (!parm->identified) - { - if (parm->line_counter == 1 && !parm->have_lf) - { - /* first line too long - assume DER encoding */ - parm->is_pem = 0; - } - else if (parm->line_counter == 1 && parm->linelen && *parm->line == 0x30) - { - /* the very first bytes does pretty much look like a SEQUENCE tag*/ - parm->is_pem = 0; - } - else if ( parm->have_lf && !strncmp (parm->line, "-----BEGIN ", 11) - && strncmp (parm->line+11, "PGP ", 4) ) - { - /* Fixme: we must only compare if the line really starts at - the beginning */ - parm->is_pem = 1; - parm->linelen = parm->readpos = 0; - } - else - { - parm->linelen = parm->readpos = 0; - goto next; - } - parm->identified = 1; - parm->base64.stop_seen = 0; - parm->base64.idx = 0; - } - - - n = 0; - if (parm->is_pem) - { - if (parm->have_lf && !strncmp (parm->line, "-----END ", 9)) - { - parm->identified = 0; - parm->linelen = parm->readpos = 0; - /* let us return 0 */ - } - else if (parm->stop_seen) - { /* skip the rest of the line */ - parm->linelen = parm->readpos = 0; - } - else - { - int idx = parm->base64.idx; - unsigned char val = parm->base64.val; - - while (n < count && parm->readpos < parm->linelen ) - { - c = parm->line[parm->readpos++]; - if (c == '\n' || c == ' ' || c == '\r' || c == '\t') - continue; - if (c == '=') - { /* pad character: stop */ - if (idx == 1) - buffer[n++] = val; - parm->stop_seen = 1; - break; - } - if( (c = asctobin[(c2=c)]) == 255 ) - { - log_error (_("invalid radix64 character %02x skipped\n"), - c2); - continue; - } - switch (idx) - { - case 0: - val = c << 2; - break; - case 1: - val |= (c>>4)&3; - buffer[n++] = val; - val = (c<<4)&0xf0; - break; - case 2: - val |= (c>>2)&15; - buffer[n++] = val; - val = (c<<6)&0xc0; - break; - case 3: - val |= c&0x3f; - buffer[n++] = val; - break; - } - idx = (idx+1) % 4; - } - if (parm->readpos == parm->linelen) - parm->linelen = parm->readpos = 0; - - parm->base64.idx = idx; - parm->base64.val = val; - } - } - else - { /* DER encoded */ - while (n < count && parm->readpos < parm->linelen) - buffer[n++] = parm->line[parm->readpos++]; - if (parm->readpos == parm->linelen) - parm->linelen = parm->readpos = 0; - } - - *nread = n; - return 0; -} - static void store_cert (KsbaCert cert) @@ -268,34 +66,23 @@ int gpgsm_import (CTRL ctrl, int in_fd) { int rc; - KsbaReader reader = NULL; + Base64Context b64reader = NULL; + KsbaReader reader; KsbaCert cert = NULL; - struct reader_cb_parm_s rparm; + FILE *fp = NULL; - memset (&rparm, 0, sizeof rparm); - - rparm.fp = fdopen ( dup (in_fd), "rb"); - if (!rparm.fp) + fp = fdopen ( dup (in_fd), "rb"); + if (!fp) { log_error ("fdopen() failed: %s\n", strerror (errno)); rc = seterr (IO_Error); goto leave; } - /* setup a skaba reader which uses a callback function so that we can - strip off a base64 encoding when necessary */ - reader = ksba_reader_new (); - if (!reader) - { - rc = seterr (Out_Of_Core); - goto leave; - } - - rc = ksba_reader_set_cb (reader, reader_cb, &rparm ); + rc = gpgsm_create_reader (&b64reader, ctrl, fp, &reader); if (rc) { - ksba_reader_release (reader); - rc = map_ksba_err (rc); + log_error ("can't create reader: %s\n", gnupg_strerror (rc)); goto leave; } @@ -318,9 +105,9 @@ gpgsm_import (CTRL ctrl, int in_fd) leave: ksba_cert_release (cert); - ksba_reader_release (reader); - if (rparm.fp) - fclose (rparm.fp); + gpgsm_destroy_reader (b64reader); + if (fp) + fclose (fp); return rc; } diff --git a/sm/server.c b/sm/server.c index e83506049..f4bb409f5 100644 --- a/sm/server.c +++ b/sm/server.c @@ -81,6 +81,43 @@ rc_to_assuan_status (int rc) } +static void +reset_notify (ASSUAN_CONTEXT ctx) +{ +} + + +static void +input_notify (ASSUAN_CONTEXT ctx, const char *line) +{ + CTRL ctrl = assuan_get_pointer (ctx); + + ctrl->autodetect_encoding = 0; + ctrl->is_pem = 0; + ctrl->is_base64 = 0; + if (strstr (line, "--armor")) + ctrl->is_pem = 1; + else if (strstr (line, "--base64")) + ctrl->is_base64 = 1; + else if (strstr (line, "--binary")) + ; + else + ctrl->autodetect_encoding = 0; +} + +static void +output_notify (ASSUAN_CONTEXT ctx, const char *line) +{ + CTRL ctrl = assuan_get_pointer (ctx); + + ctrl->create_pem = 0; + ctrl->create_base64 = 0; + if (strstr (line, "--armor")) + ctrl->create_pem = 1; + else if (strstr (line, "--base64")) + ctrl->create_base64 = 1; /* just the raw output */ +} + /* RECIPIENT @@ -103,7 +140,7 @@ cmd_recipient (ASSUAN_CONTEXT ctx, char *line) } -/* ENCRYPT [armor] +/* ENCRYPT Do the actual encryption process. Takes the plaintext from the INPUT command, writes to the ciphertext to the file descriptor set with @@ -115,16 +152,28 @@ cmd_recipient (ASSUAN_CONTEXT ctx, char *line) This command should in general not fail, as all necessary checks have been done while setting the recipients. The input and output - pipes are closed. - - The optional armor parameter may be used to request base64 encoded - output. */ + pipes are closed. */ static int cmd_encrypt (ASSUAN_CONTEXT ctx, char *line) { - + int inp_fd, out_fd; + FILE *out_fp; + int rc; - return set_error (Not_Implemented, "fixme"); + 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_encrypt (assuan_get_pointer (ctx), inp_fd, out_fp); + fclose (out_fp); + + return rc_to_assuan_status (rc); } /* DECRYPT @@ -172,7 +221,7 @@ cmd_verify (ASSUAN_CONTEXT ctx, char *line) /* SIGN [--detached] Sign the data set with the INPUT command and write it to the sink - set by OUTPUT. with "--detached" specified, a detached signature is + set by OUTPUT. With "--detached" specified, a detached signature is created (surprise). */ static int cmd_sign (ASSUAN_CONTEXT ctx, char *line) @@ -330,6 +379,10 @@ gpgsm_server (void) gpgsm_exit (2); } + assuan_register_reset_notify (ctx, reset_notify); + assuan_register_input_notify (ctx, input_notify); + assuan_register_output_notify (ctx, output_notify); + assuan_set_pointer (ctx, &ctrl); ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local); ctrl.server_local->assuan_ctx = ctx; diff --git a/sm/sign.c b/sm/sign.c index a246511e3..42f409a7d 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -35,14 +35,6 @@ #include "i18n.h" - - -struct reader_cb_parm_s { - FILE *fp; -}; - - - static void hash_data (int fd, GCRY_MD_HD md) { @@ -112,19 +104,17 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) { int i, rc; KsbaError err; - KsbaWriter writer = NULL; + Base64Context b64writer = NULL; + KsbaWriter writer; KsbaCMS cms = NULL; KsbaStopReason stopreason; KsbaCert cert; KEYDB_HANDLE kh = NULL; GCRY_MD_HD data_md = NULL; - struct reader_cb_parm_s rparm; int signer; const char *algoid; int algo; - memset (&rparm, 0, sizeof rparm); - if (!detached) { rc = seterr (Not_Implemented); @@ -140,25 +130,10 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) goto leave; } - rparm.fp = fdopen ( dup (data_fd), "rb"); - if (!rparm.fp) - { - log_error ("fdopen() failed: %s\n", strerror (errno)); - rc = seterr (IO_Error); - goto leave; - } - - writer = ksba_writer_new (); - if (!writer) - { - rc = seterr (Out_Of_Core); - goto leave; - } - rc = ksba_writer_set_file (writer, out_fp); + rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer); if (rc) { - ksba_writer_release (writer); - rc = map_ksba_err (rc); + log_error ("can't create writer: %s\n", gnupg_strerror (rc)); goto leave; } @@ -357,10 +332,8 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) leave: ksba_cms_release (cms); - ksba_writer_release (writer); + gpgsm_destroy_writer (b64writer); keydb_release (kh); gcry_md_close (data_md); - if (rparm.fp) - fclose (rparm.fp); return rc; } diff --git a/sm/verify.c b/sm/verify.c index 5b3a5a848..6f4a1d2c0 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -34,11 +34,6 @@ #include "keydb.h" #include "i18n.h" -struct reader_cb_parm_s { - FILE *fp; -}; - - /* FIXME: Move this to jnlib */ static char * strtimestamp (time_t atime) @@ -46,9 +41,9 @@ strtimestamp (time_t atime) char *buffer = xmalloc (15); if (atime < 0) - { - strcpy (buffer, "????" "-??" "-??"); - } + strcpy (buffer, "????" "-??" "-??"); + else if (!atime) + strcpy (buffer, "none"); else { struct tm *tp; @@ -62,38 +57,6 @@ strtimestamp (time_t atime) - -/* FIXME: We need to write a generic reader callback which should be able - to detect and convert base-64 */ -static int -reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread) -{ - struct reader_cb_parm_s *parm = cb_value; - size_t n; - int c = 0; - - *nread = 0; - if (!buffer) - return -1; /* not supported */ - - for (n=0; n < count; n++) - { - c = getc (parm->fp); - if (c == EOF) - { - if ( ferror (parm->fp) ) - return -1; - if (n) - break; /* return what we have before an EOF */ - return -1; - } - *(byte *)buffer++ = c; - } - - *nread = n; - return 0; -} - /* fixme: duplicated from import.c */ static void store_cert (KsbaCert cert) @@ -192,21 +155,19 @@ int gpgsm_verify (CTRL ctrl, int in_fd, int data_fd) { int i, rc; + Base64Context b64reader = NULL; KsbaError err; - KsbaReader reader = NULL; - KsbaWriter writer = NULL; + KsbaReader reader; KsbaCMS cms = NULL; KsbaStopReason stopreason; KsbaCert cert; KEYDB_HANDLE kh; GCRY_MD_HD data_md = NULL; - struct reader_cb_parm_s rparm; int signer; const char *algoid; int algo; int is_detached; - - memset (&rparm, 0, sizeof rparm); + FILE *fp = NULL; kh = keydb_new (0); if (!kh) @@ -217,29 +178,18 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd) } - rparm.fp = fdopen ( dup (in_fd), "rb"); - if (!rparm.fp) + fp = fdopen ( dup (in_fd), "rb"); + if (!fp) { log_error ("fdopen() failed: %s\n", strerror (errno)); rc = seterr (IO_Error); goto leave; } - /* setup a skaba reader which uses a callback function so that we can - strip off a base64 encoding when necessary */ - reader = ksba_reader_new (); - writer = ksba_writer_new (); - if (!reader || !writer) - { - rc = seterr (Out_Of_Core); - goto leave; - } - - rc = ksba_reader_set_cb (reader, reader_cb, &rparm ); + rc = gpgsm_create_reader (&b64reader, ctrl, fp, &reader); if (rc) { - ksba_reader_release (reader); - rc = map_ksba_err (rc); + log_error ("can't create reader: %s\n", gnupg_strerror (rc)); goto leave; } @@ -250,7 +200,7 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd) goto leave; } - err = ksba_cms_set_reader_writer (cms, reader, writer); + err = ksba_cms_set_reader_writer (cms, reader, NULL); if (err) { log_debug ("ksba_cms_set_reader_writer failed: %s\n", @@ -454,9 +404,9 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd) char *buf, *fpr, *tstr; fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1); - tstr = strtimestamp ( 42 /*fixme: get right time */); + tstr = strtimestamp (sigtime); buf = xmalloc ( strlen(fpr) + strlen (tstr) + 100); - sprintf (buf, "%s %s %lu", fpr, tstr, (unsigned long)42 ); + sprintf (buf, "%s %s %lu", fpr, tstr, (unsigned long)sigtime ); xfree (tstr); xfree (fpr); gpgsm_status (ctrl, STATUS_VALIDSIG, buf); @@ -498,11 +448,11 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd) leave: ksba_cms_release (cms); - ksba_reader_release (reader); + gpgsm_destroy_reader (b64reader); keydb_release (kh); gcry_md_close (data_md); - if (rparm.fp) - fclose (rparm.fp); + if (fp) + fclose (fp); return rc; }