1 /* kska-io-support.c - Supporting functions for ksba reader and writer
2 * Copyright (C) 2001-2005, 2007, 2010-2011, 2017 Werner Koch
3 * Copyright (C) 2006 g10 Code GmbH
5 * This file is part of GnuPG.
7 * This file is free software; you can redistribute it and/or modify
8 * it under the terms of either
10 * - the GNU Lesser General Public License as published by the Free
11 * Software Foundation; either version 3 of the License, or (at
12 * your option) any later version.
16 * - the GNU General Public License as published by the Free
17 * Software Foundation; either version 2 of the License, or (at
18 * your option) any later version.
20 * or both in parallel, as here.
22 * This file is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, see <https://www.gnu.org/licenses/>.
43 #include "ksba-io-support.h"
46 #ifdef HAVE_DOSISH_SYSTEM
53 /* Data used by the reader callbacks. */
54 struct reader_cb_parm_s
58 unsigned char line[1024];
62 unsigned long line_counter;
64 int allow_multi_pem; /* Allow processing of multiple PEM objects. */
65 int autodetect; /* Try to detect the input encoding. */
66 int assume_pem; /* Assume input encoding is PEM. */
67 int assume_base64; /* Assume input is base64 encoded. */
85 /* Data used by the writer callbacks. */
86 struct writer_cb_parm_s
88 estream_t stream; /* Output stream. */
90 char *pem_name; /* Malloced. */
98 unsigned char radbuf[4];
104 /* Context for this module's functions. */
105 struct gnupg_ksba_io_s {
107 struct reader_cb_parm_s rparm;
108 struct writer_cb_parm_s wparm;
112 ksba_reader_t reader;
113 ksba_writer_t writer;
118 /* The base-64 character list */
119 static char bintoasc[64] =
120 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
121 "abcdefghijklmnopqrstuvwxyz"
123 /* The reverse base-64 list */
124 static unsigned char asctobin[256] = {
125 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
126 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
127 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
128 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
129 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
130 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
131 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
132 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
133 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
134 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
135 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
136 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
137 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
138 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
139 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
140 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
141 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
142 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
143 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
144 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
145 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
146 0xff, 0xff, 0xff, 0xff
151 has_only_base64 (const unsigned char *line, int linelen)
155 for (; linelen; line++, linelen--)
157 if (*line == '\n' || (linelen > 1 && *line == '\r' && line[1] == '\n'))
159 if ( !strchr (bintoasc, *line) )
166 is_empty_line (const unsigned char *line, int linelen)
168 if (linelen >= 2 && *line == '\r' && line[1] == '\n')
170 if (linelen >= 1 && *line == '\n')
177 base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
179 struct reader_cb_parm_s *parm = cb_value;
185 return -1; /* not supported */
190 /* read an entire line or up to the size of the buffer */
191 parm->line_counter++;
193 for (n=0; n < DIM(parm->line);)
195 c = es_getc (parm->fp);
199 if (es_ferror (parm->fp))
207 /* Fixme: we need to skip overlong lines while detecting
218 if (!parm->identified)
220 if (!parm->autodetect)
222 if (parm->assume_pem)
224 /* wait for the header line */
225 parm->linelen = parm->readpos = 0;
227 || strncmp ((char*)parm->line, "-----BEGIN ", 11)
228 || !strncmp ((char*)parm->line+11, "PGP ", 4))
232 else if (parm->assume_base64)
235 else if (parm->line_counter == 1 && !parm->have_lf)
237 /* first line too long - assume DER encoding */
240 else if (parm->line_counter == 1 && parm->linelen && *parm->line == 0x30)
242 /* the very first byte does pretty much look like a SEQUENCE tag*/
245 else if ( parm->have_lf
246 && !strncmp ((char*)parm->line, "-----BEGIN ", 11)
247 && strncmp ((char *)parm->line+11, "PGP ", 4) )
249 /* Fixme: we must only compare if the line really starts at
252 parm->linelen = parm->readpos = 0;
254 else if ( parm->have_lf && parm->line_counter == 1
255 && parm->linelen >= 13
256 && !ascii_memcasecmp (parm->line, "Content-Type:", 13))
257 { /* might be a S/MIME body */
258 parm->might_be_smime = 1;
259 parm->linelen = parm->readpos = 0;
262 else if (parm->might_be_smime == 1
263 && is_empty_line (parm->line, parm->linelen))
265 parm->might_be_smime = 2;
266 parm->linelen = parm->readpos = 0;
269 else if (parm->might_be_smime == 2)
271 parm->might_be_smime = 0;
272 if ( !has_only_base64 (parm->line, parm->linelen))
274 parm->linelen = parm->readpos = 0;
281 parm->linelen = parm->readpos = 0;
284 parm->identified = 1;
285 parm->base64.stop_seen = 0;
286 parm->base64.idx = 0;
291 if (parm->is_pem || parm->is_base64)
293 if (parm->is_pem && parm->have_lf
294 && !strncmp ((char*)parm->line, "-----END ", 9))
296 parm->identified = 0;
297 parm->linelen = parm->readpos = 0;
299 /* If the caller want to read multiple PEM objects from one
300 file, we have to reset our internal state and return a
301 EOF immediately. The caller is the expected to use
302 ksba_reader_clear to clear the EOF condition and continue
303 to read. If we don't want to do that we just return 0
304 bytes which will force the ksba_reader to skip until
306 if (parm->allow_multi_pem)
308 parm->identified = 0;
309 parm->autodetect = 0;
310 parm->assume_pem = 1;
312 return -1; /* Send EOF now. */
315 else if (parm->stop_seen)
316 { /* skip the rest of the line */
317 parm->linelen = parm->readpos = 0;
321 int idx = parm->base64.idx;
322 unsigned char val = parm->base64.val;
324 while (n < count && parm->readpos < parm->linelen )
326 c = parm->line[parm->readpos++];
327 if (c == '\n' || c == ' ' || c == '\r' || c == '\t')
330 { /* pad character: stop */
336 if( (c = asctobin[(c2=c)]) == 255 )
338 log_error (_("invalid radix64 character %02x skipped\n"),
364 if (parm->readpos == parm->linelen)
365 parm->linelen = parm->readpos = 0;
367 parm->base64.idx = idx;
368 parm->base64.val = val;
373 while (n < count && parm->readpos < parm->linelen)
374 buffer[n++] = parm->line[parm->readpos++];
375 if (parm->readpos == parm->linelen)
376 parm->linelen = parm->readpos = 0;
386 simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
388 struct reader_cb_parm_s *parm = cb_value;
394 return -1; /* not supported */
396 for (n=0; n < count; n++)
398 c = es_getc (parm->fp);
402 if (es_ferror (parm->fp))
405 break; /* Return what we have before an EOF. */
408 *(byte *)buffer++ = c;
419 base64_writer_cb (void *cb_value, const void *buffer, size_t count)
421 struct writer_cb_parm_s *parm = cb_value;
422 unsigned char radbuf[4];
423 int i, c, idx, quad_count;
424 const unsigned char *p;
425 estream_t stream = parm->stream;
430 if (!parm->wrote_begin)
434 es_fputs ("-----BEGIN ", stream);
435 es_fputs (parm->pem_name, stream);
436 es_fputs ("-----\n", stream);
438 parm->wrote_begin = 1;
439 parm->base64.idx = 0;
440 parm->base64.quad_count = 0;
443 idx = parm->base64.idx;
444 quad_count = parm->base64.quad_count;
445 for (i=0; i < idx; i++)
446 radbuf[i] = parm->base64.radbuf[i];
448 for (p=buffer; count; p++, count--)
454 c = bintoasc[(*radbuf >> 2) & 077];
456 c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
458 c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
460 c = bintoasc[radbuf[2]&077];
462 if (++quad_count >= (64/4))
464 es_fputs (LF, stream);
469 for (i=0; i < idx; i++)
470 parm->base64.radbuf[i] = radbuf[i];
471 parm->base64.idx = idx;
472 parm->base64.quad_count = quad_count;
474 return es_ferror (stream)? gpg_error_from_syserror () : 0;
478 /* This callback is only used in stream mode. However, we don't
479 restrict it to this. */
481 plain_writer_cb (void *cb_value, const void *buffer, size_t count)
483 struct writer_cb_parm_s *parm = cb_value;
484 estream_t stream = parm->stream;
489 es_write (stream, buffer, count, NULL);
491 return es_ferror (stream)? gpg_error_from_syserror () : 0;
496 base64_finish_write (struct writer_cb_parm_s *parm)
498 unsigned char *radbuf;
499 int c, idx, quad_count;
500 estream_t stream = parm->stream;
502 if (!parm->wrote_begin)
503 return 0; /* Nothing written or we are not called in base-64 mode. */
505 /* flush the base64 encoding */
506 idx = parm->base64.idx;
507 quad_count = parm->base64.quad_count;
510 radbuf = parm->base64.radbuf;
512 c = bintoasc[(*radbuf>>2)&077];
516 c = bintoasc[((*radbuf << 4) & 060) & 077];
518 es_putc ('=', stream);
519 es_putc ('=', stream);
523 c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
525 c = bintoasc[((radbuf[1] << 2) & 074) & 077];
527 es_putc ('=', stream);
530 if (++quad_count >= (64/4))
532 es_fputs (LF, stream);
538 es_fputs (LF, stream);
542 es_fputs ("-----END ", stream);
543 es_fputs (parm->pem_name, stream);
544 es_fputs ("-----\n", stream);
547 return es_ferror (stream)? gpg_error_from_syserror () : 0;
553 /* Create a reader for the stream FP. FLAGS can be used to specify
554 * the expected input encoding.
556 * The function returns a gnupg_ksba_io_t object which must be passed to
557 * the gpgme_destroy_reader function. The created ksba_reader_t
558 * object is stored at R_READER - the caller must not call the
559 * ksba_reader_release function on.
561 * The supported flags are:
563 * GNUPG_KSBA_IO_PEM - Assume the input is PEM encoded
564 * GNUPG_KSBA_IO_BASE64 - Assume the input is Base64 encoded.
565 * GNUPG_KSBA_IO_AUTODETECT - The reader tries to detect the encoding.
566 * GNUPG_KSBA_IO_MULTIPEM - The reader expects that the caller uses
567 * ksba_reader_clear after EOF until no more
568 * objects were found.
570 * Note that the PEM flag has a higher priority than the BASE64 flag
571 * which in turn has a gight priority than the AUTODETECT flag.
574 gnupg_ksba_create_reader (gnupg_ksba_io_t *ctx,
575 unsigned int flags, estream_t fp,
576 ksba_reader_t *r_reader)
582 *ctx = xtrycalloc (1, sizeof **ctx);
584 return out_of_core ();
585 (*ctx)->u.rparm.allow_multi_pem = !!(flags & GNUPG_KSBA_IO_MULTIPEM);
587 rc = ksba_reader_new (&r);
590 xfree (*ctx); *ctx = NULL;
594 (*ctx)->u.rparm.fp = fp;
595 if ((flags & GNUPG_KSBA_IO_PEM))
597 (*ctx)->u.rparm.assume_pem = 1;
598 (*ctx)->u.rparm.assume_base64 = 1;
599 rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
601 else if ((flags & GNUPG_KSBA_IO_BASE64))
603 (*ctx)->u.rparm.assume_base64 = 1;
604 rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
606 else if ((flags & GNUPG_KSBA_IO_AUTODETECT))
608 (*ctx)->u.rparm.autodetect = 1;
609 rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
612 rc = ksba_reader_set_cb (r, simple_reader_cb, &(*ctx)->u.rparm);
616 ksba_reader_release (r);
617 xfree (*ctx); *ctx = NULL;
621 (*ctx)->u2.reader = r;
627 /* Return True if an EOF as been seen. */
629 gnupg_ksba_reader_eof_seen (gnupg_ksba_io_t ctx)
631 return ctx && ctx->u.rparm.eof_seen;
635 /* Destroy a reader object. */
637 gnupg_ksba_destroy_reader (gnupg_ksba_io_t ctx)
642 ksba_reader_release (ctx->u2.reader);
648 /* Create a writer for the given STREAM. Depending on FLAGS an output
649 * encoding is chosen. In PEM mode PEM_NAME is used for the header
650 * and footer lines; if PEM_NAME is NULL the string "CMS OBJECT" is
653 * The function returns a gnupg_ksba_io_t object which must be passed to
654 * the gpgme_destroy_writer function. The created ksba_writer_t
655 * object is stored at R_WRITER - the caller must not call the
656 * ksba_reader_release function on it.
658 * The supported flags are:
660 * GNUPG_KSBA_IO_PEM - Write output as PEM
661 * GNUPG_KSBA_IO_BASE64 - Write output as plain Base64; note that the PEM
662 * flag overrides this flag.
666 gnupg_ksba_create_writer (gnupg_ksba_io_t *ctx, unsigned int flags,
667 const char *pem_name, estream_t stream,
668 ksba_writer_t *r_writer)
674 *ctx = xtrycalloc (1, sizeof **ctx);
676 return gpg_error_from_syserror ();
678 rc = ksba_writer_new (&w);
681 xfree (*ctx); *ctx = NULL;
685 if ((flags & GNUPG_KSBA_IO_PEM) || (flags & GNUPG_KSBA_IO_BASE64))
687 (*ctx)->u.wparm.stream = stream;
688 if ((flags & GNUPG_KSBA_IO_PEM))
690 (*ctx)->u.wparm.pem_name = xtrystrdup (pem_name
693 if (!(*ctx)->u.wparm.pem_name)
695 rc = gpg_error_from_syserror ();
696 ksba_writer_release (w);
697 xfree (*ctx); *ctx = NULL;
701 rc = ksba_writer_set_cb (w, base64_writer_cb, &(*ctx)->u.wparm);
705 (*ctx)->u.wparm.stream = stream;
706 rc = ksba_writer_set_cb (w, plain_writer_cb, &(*ctx)->u.wparm);
709 rc = gpg_error (GPG_ERR_INV_ARG);
713 ksba_writer_release (w);
714 xfree (*ctx); *ctx = NULL;
718 (*ctx)->u2.writer = w;
724 /* Flush a writer. This is for example required to write the padding
725 * or the PEM footer. */
727 gnupg_ksba_finish_writer (gnupg_ksba_io_t ctx)
729 struct writer_cb_parm_s *parm;
732 return gpg_error (GPG_ERR_INV_VALUE);
733 parm = &ctx->u.wparm;
734 if (parm->did_finish)
735 return 0; /* Already done. */
736 parm->did_finish = 1;
738 return 0; /* Callback was not used. */
739 return base64_finish_write (parm);
743 /* Destroy a writer object. */
745 gnupg_ksba_destroy_writer (gnupg_ksba_io_t ctx)
750 ksba_writer_release (ctx->u2.writer);
751 xfree (ctx->u.wparm.pem_name);