2 * Copyright (C) 2001, 2003, 2010 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <https://www.gnu.org/licenses/>.
36 #ifdef HAVE_DOSISH_SYSTEM
42 /* Data used by the reader callbacks. */
43 struct reader_cb_parm_s
47 unsigned char line[1024];
51 unsigned long line_counter;
53 int allow_multi_pem; /* Allow processing of multiple PEM objects. */
54 int autodetect; /* Try to detect the input encoding. */
55 int assume_pem; /* Assume input encoding is PEM. */
56 int assume_base64; /* Assume input is base64 encoded. */
74 /* Data used by the writer callbacks. */
75 struct writer_cb_parm_s
77 estream_t stream; /* Output stream. */
87 unsigned char radbuf[4];
93 /* context for this module's functions */
94 struct base64_context_s {
96 struct reader_cb_parm_s rparm;
97 struct writer_cb_parm_s wparm;
101 ksba_reader_t reader;
102 ksba_writer_t writer;
107 /* The base-64 character list */
108 static char bintoasc[64] =
109 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
110 "abcdefghijklmnopqrstuvwxyz"
112 /* The reverse base-64 list */
113 static unsigned char asctobin[256] = {
114 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
115 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
116 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
117 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
118 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
119 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
120 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
121 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
122 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
123 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
124 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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, 0xff, 0xff, 0xff, 0xff, 0xff,
129 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
130 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
131 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
132 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
133 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
134 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
135 0xff, 0xff, 0xff, 0xff
140 has_only_base64 (const unsigned char *line, int linelen)
144 for (; linelen; line++, linelen--)
146 if (*line == '\n' || (linelen > 1 && *line == '\r' && line[1] == '\n'))
148 if ( !strchr (bintoasc, *line) )
155 is_empty_line (const unsigned char *line, int linelen)
157 if (linelen >= 2 && *line == '\r' && line[1] == '\n')
159 if (linelen >= 1 && *line == '\n')
166 base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
168 struct reader_cb_parm_s *parm = cb_value;
174 return -1; /* not supported */
179 /* read an entire line or up to the size of the buffer */
180 parm->line_counter++;
182 for (n=0; n < DIM(parm->line);)
184 c = es_getc (parm->fp);
188 if (es_ferror (parm->fp))
196 /* Fixme: we need to skip overlong lines while detecting
207 if (!parm->identified)
209 if (!parm->autodetect)
211 if (parm->assume_pem)
213 /* wait for the header line */
214 parm->linelen = parm->readpos = 0;
216 || strncmp ((char*)parm->line, "-----BEGIN ", 11)
217 || !strncmp ((char*)parm->line+11, "PGP ", 4))
221 else if (parm->assume_base64)
224 else if (parm->line_counter == 1 && !parm->have_lf)
226 /* first line too long - assume DER encoding */
229 else if (parm->line_counter == 1 && parm->linelen && *parm->line == 0x30)
231 /* the very first byte does pretty much look like a SEQUENCE tag*/
234 else if ( parm->have_lf
235 && !strncmp ((char*)parm->line, "-----BEGIN ", 11)
236 && strncmp ((char *)parm->line+11, "PGP ", 4) )
238 /* Fixme: we must only compare if the line really starts at
241 parm->linelen = parm->readpos = 0;
243 else if ( parm->have_lf && parm->line_counter == 1
244 && parm->linelen >= 13
245 && !ascii_memcasecmp (parm->line, "Content-Type:", 13))
246 { /* might be a S/MIME body */
247 parm->might_be_smime = 1;
248 parm->linelen = parm->readpos = 0;
251 else if (parm->might_be_smime == 1
252 && is_empty_line (parm->line, parm->linelen))
254 parm->might_be_smime = 2;
255 parm->linelen = parm->readpos = 0;
258 else if (parm->might_be_smime == 2)
260 parm->might_be_smime = 0;
261 if ( !has_only_base64 (parm->line, parm->linelen))
263 parm->linelen = parm->readpos = 0;
270 parm->linelen = parm->readpos = 0;
273 parm->identified = 1;
274 parm->base64.stop_seen = 0;
275 parm->base64.idx = 0;
280 if (parm->is_pem || parm->is_base64)
282 if (parm->is_pem && parm->have_lf
283 && !strncmp ((char*)parm->line, "-----END ", 9))
285 parm->identified = 0;
286 parm->linelen = parm->readpos = 0;
288 /* If the caller want to read multiple PEM objects from one
289 file, we have to reset our internal state and return a
290 EOF immediately. The caller is the expected to use
291 ksba_reader_clear to clear the EOF condition and continue
292 to read. If we don't want to do that we just return 0
293 bytes which will force the ksba_reader to skip until
295 if (parm->allow_multi_pem)
297 parm->identified = 0;
298 parm->autodetect = 0;
299 parm->assume_pem = 1;
301 return -1; /* Send EOF now. */
304 else if (parm->stop_seen)
305 { /* skip the rest of the line */
306 parm->linelen = parm->readpos = 0;
310 int idx = parm->base64.idx;
311 unsigned char val = parm->base64.val;
313 while (n < count && parm->readpos < parm->linelen )
315 c = parm->line[parm->readpos++];
316 if (c == '\n' || c == ' ' || c == '\r' || c == '\t')
319 { /* pad character: stop */
325 if( (c = asctobin[(c2=c)]) == 255 )
327 log_error (_("invalid radix64 character %02x skipped\n"),
353 if (parm->readpos == parm->linelen)
354 parm->linelen = parm->readpos = 0;
356 parm->base64.idx = idx;
357 parm->base64.val = val;
362 while (n < count && parm->readpos < parm->linelen)
363 buffer[n++] = parm->line[parm->readpos++];
364 if (parm->readpos == parm->linelen)
365 parm->linelen = parm->readpos = 0;
375 simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
377 struct reader_cb_parm_s *parm = cb_value;
383 return -1; /* not supported */
385 for (n=0; n < count; n++)
387 c = es_getc (parm->fp);
391 if (es_ferror (parm->fp))
394 break; /* Return what we have before an EOF. */
397 *(byte *)buffer++ = c;
408 base64_writer_cb (void *cb_value, const void *buffer, size_t count)
410 struct writer_cb_parm_s *parm = cb_value;
411 unsigned char radbuf[4];
412 int i, c, idx, quad_count;
413 const unsigned char *p;
414 estream_t stream = parm->stream;
419 if (!parm->wrote_begin)
423 es_fputs ("-----BEGIN ", stream);
424 es_fputs (parm->pem_name, stream);
425 es_fputs ("-----\n", stream);
427 parm->wrote_begin = 1;
428 parm->base64.idx = 0;
429 parm->base64.quad_count = 0;
432 idx = parm->base64.idx;
433 quad_count = parm->base64.quad_count;
434 for (i=0; i < idx; i++)
435 radbuf[i] = parm->base64.radbuf[i];
437 for (p=buffer; count; p++, count--)
443 c = bintoasc[(*radbuf >> 2) & 077];
445 c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
447 c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
449 c = bintoasc[radbuf[2]&077];
451 if (++quad_count >= (64/4))
453 es_fputs (LF, stream);
458 for (i=0; i < idx; i++)
459 parm->base64.radbuf[i] = radbuf[i];
460 parm->base64.idx = idx;
461 parm->base64.quad_count = quad_count;
463 return es_ferror (stream)? gpg_error_from_syserror () : 0;
467 /* This callback is only used in stream mode. Hiowever, we don't
468 restrict it to this. */
470 plain_writer_cb (void *cb_value, const void *buffer, size_t count)
472 struct writer_cb_parm_s *parm = cb_value;
473 estream_t stream = parm->stream;
478 es_write (stream, buffer, count, NULL);
480 return es_ferror (stream)? gpg_error_from_syserror () : 0;
485 base64_finish_write (struct writer_cb_parm_s *parm)
487 unsigned char *radbuf;
488 int c, idx, quad_count;
489 estream_t stream = parm->stream;
491 if (!parm->wrote_begin)
492 return 0; /* Nothing written or we are not called in base-64 mode. */
494 /* flush the base64 encoding */
495 idx = parm->base64.idx;
496 quad_count = parm->base64.quad_count;
499 radbuf = parm->base64.radbuf;
501 c = bintoasc[(*radbuf>>2)&077];
505 c = bintoasc[((*radbuf << 4) & 060) & 077];
507 es_putc ('=', stream);
508 es_putc ('=', stream);
512 c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
514 c = bintoasc[((radbuf[1] << 2) & 074) & 077];
516 es_putc ('=', stream);
519 if (++quad_count >= (64/4))
521 es_fputs (LF, stream);
527 es_fputs (LF, stream);
531 es_fputs ("-----END ", stream);
532 es_fputs (parm->pem_name, stream);
533 es_fputs ("-----\n", stream);
536 return es_ferror (stream)? gpg_error_from_syserror () : 0;
542 /* Create a reader for the given file descriptor. Depending on the
543 control information an input decoding is automagically chosen.
544 The function returns a Base64Context object which must be passed to
545 the gpgme_destroy_reader function. The created KsbaReader object
546 is also returned, but the caller must not call the
547 ksba_reader_release function on. If ALLOW_MULTI_PEM is true, the
548 reader expects that the caller uses ksba_reader_clear after EOF
549 until no more objects were found. */
551 gpgsm_create_reader (Base64Context *ctx,
552 ctrl_t ctrl, estream_t fp, int allow_multi_pem,
553 ksba_reader_t *r_reader)
559 *ctx = xtrycalloc (1, sizeof **ctx);
561 return out_of_core ();
562 (*ctx)->u.rparm.allow_multi_pem = allow_multi_pem;
564 rc = ksba_reader_new (&r);
567 xfree (*ctx); *ctx = NULL;
571 (*ctx)->u.rparm.fp = fp;
574 (*ctx)->u.rparm.assume_pem = 1;
575 (*ctx)->u.rparm.assume_base64 = 1;
576 rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
578 else if (ctrl->is_base64)
580 (*ctx)->u.rparm.assume_base64 = 1;
581 rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
583 else if (ctrl->autodetect_encoding)
585 (*ctx)->u.rparm.autodetect = 1;
586 rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
589 rc = ksba_reader_set_cb (r, simple_reader_cb, &(*ctx)->u.rparm);
593 ksba_reader_release (r);
594 xfree (*ctx); *ctx = NULL;
598 (*ctx)->u2.reader = r;
605 gpgsm_reader_eof_seen (Base64Context ctx)
607 return ctx && ctx->u.rparm.eof_seen;
611 gpgsm_destroy_reader (Base64Context ctx)
616 ksba_reader_release (ctx->u2.reader);
622 /* Create a writer for the given STREAM. Depending on
623 the control information an output encoding is automagically
624 chosen. The function returns a Base64Context object which must be
625 passed to the gpgme_destroy_writer function. The created
626 KsbaWriter object is also returned, but the caller must not call
627 the ksba_reader_release function on it. */
629 gpgsm_create_writer (Base64Context *ctx, ctrl_t ctrl, estream_t stream,
630 ksba_writer_t *r_writer)
636 *ctx = xtrycalloc (1, sizeof **ctx);
638 return out_of_core ();
640 rc = ksba_writer_new (&w);
643 xfree (*ctx); *ctx = NULL;
647 if (ctrl->create_pem || ctrl->create_base64)
649 (*ctx)->u.wparm.stream = stream;
650 if (ctrl->create_pem)
651 (*ctx)->u.wparm.pem_name = ctrl->pem_name? ctrl->pem_name
653 rc = ksba_writer_set_cb (w, base64_writer_cb, &(*ctx)->u.wparm);
657 (*ctx)->u.wparm.stream = stream;
658 rc = ksba_writer_set_cb (w, plain_writer_cb, &(*ctx)->u.wparm);
661 rc = gpg_error (GPG_ERR_INV_ARG);
665 ksba_writer_release (w);
666 xfree (*ctx); *ctx = NULL;
670 (*ctx)->u2.writer = w;
677 gpgsm_finish_writer (Base64Context ctx)
679 struct writer_cb_parm_s *parm;
682 return gpg_error (GPG_ERR_INV_VALUE);
683 parm = &ctx->u.wparm;
684 if (parm->did_finish)
685 return 0; /* Already done. */
686 parm->did_finish = 1;
688 return 0; /* Callback was not used. */
689 return base64_finish_write (parm);
693 gpgsm_destroy_writer (Base64Context ctx)
698 ksba_writer_release (ctx->u2.writer);