2 * Copyright (C) 2001, 2003 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 <http://www.gnu.org/licenses/>.
36 #ifdef HAVE_DOSISH_SYSTEM
42 /* data used by the reader callbacks */
43 struct reader_cb_parm_s
{
46 unsigned char line
[1024];
50 unsigned long line_counter
;
52 int allow_multi_pem
; /* Allow processing of multiple PEM objects. */
53 int autodetect
; /* Try to detect the input encoding. */
54 int assume_pem
; /* Assume input encoding is PEM. */
55 int assume_base64
; /* Assume input is base64 encoded. */
72 /* data used by the writer callbacks */
73 struct writer_cb_parm_s
{
74 FILE *fp
; /* FP is only used if STREAM is NULL. */
75 estream_t stream
; /* Alternative output if not NULL. */
85 unsigned char radbuf
[4];
91 /* context for this module's functions */
92 struct base64_context_s
{
94 struct reader_cb_parm_s rparm
;
95 struct writer_cb_parm_s wparm
;
100 ksba_writer_t writer
;
105 /* The base-64 character list */
106 static char bintoasc
[64] =
107 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
108 "abcdefghijklmnopqrstuvwxyz"
110 /* The reverse base-64 list */
111 static unsigned char asctobin
[256] = {
112 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
113 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
114 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
115 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
116 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
117 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
118 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
119 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
120 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
121 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
122 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
123 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
124 0xff, 0xff, 0xff, 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
138 has_only_base64 (const unsigned char *line
, int linelen
)
142 for (; linelen
; line
++, linelen
--)
144 if (*line
== '\n' || (linelen
> 1 && *line
== '\r' && line
[1] == '\n'))
146 if ( !strchr (bintoasc
, *line
) )
153 is_empty_line (const unsigned char *line
, int linelen
)
155 if (linelen
>= 2 && *line
== '\r' && line
[1] == '\n')
157 if (linelen
>= 1 && *line
== '\n')
164 base64_reader_cb (void *cb_value
, char *buffer
, size_t count
, size_t *nread
)
166 struct reader_cb_parm_s
*parm
= cb_value
;
172 return -1; /* not supported */
177 /* read an entire line or up to the size of the buffer */
178 parm
->line_counter
++;
180 for (n
=0; n
< DIM(parm
->line
);)
186 if (ferror (parm
->fp
))
194 /* Fixme: we need to skip overlong lines while detecting
205 if (!parm
->identified
)
207 if (!parm
->autodetect
)
209 if (parm
->assume_pem
)
211 /* wait for the header line */
212 parm
->linelen
= parm
->readpos
= 0;
214 || strncmp ((char*)parm
->line
, "-----BEGIN ", 11)
215 || !strncmp ((char*)parm
->line
+11, "PGP ", 4))
219 else if (parm
->assume_base64
)
222 else if (parm
->line_counter
== 1 && !parm
->have_lf
)
224 /* first line too long - assume DER encoding */
227 else if (parm
->line_counter
== 1 && parm
->linelen
&& *parm
->line
== 0x30)
229 /* the very first byte does pretty much look like a SEQUENCE tag*/
232 else if ( parm
->have_lf
233 && !strncmp ((char*)parm
->line
, "-----BEGIN ", 11)
234 && strncmp ((char *)parm
->line
+11, "PGP ", 4) )
236 /* Fixme: we must only compare if the line really starts at
239 parm
->linelen
= parm
->readpos
= 0;
241 else if ( parm
->have_lf
&& parm
->line_counter
== 1
242 && parm
->linelen
>= 13
243 && !ascii_memcasecmp (parm
->line
, "Content-Type:", 13))
244 { /* might be a S/MIME body */
245 parm
->might_be_smime
= 1;
246 parm
->linelen
= parm
->readpos
= 0;
249 else if (parm
->might_be_smime
== 1
250 && is_empty_line (parm
->line
, parm
->linelen
))
252 parm
->might_be_smime
= 2;
253 parm
->linelen
= parm
->readpos
= 0;
256 else if (parm
->might_be_smime
== 2)
258 parm
->might_be_smime
= 0;
259 if ( !has_only_base64 (parm
->line
, parm
->linelen
))
261 parm
->linelen
= parm
->readpos
= 0;
268 parm
->linelen
= parm
->readpos
= 0;
271 parm
->identified
= 1;
272 parm
->base64
.stop_seen
= 0;
273 parm
->base64
.idx
= 0;
278 if (parm
->is_pem
|| parm
->is_base64
)
280 if (parm
->is_pem
&& parm
->have_lf
281 && !strncmp ((char*)parm
->line
, "-----END ", 9))
283 parm
->identified
= 0;
284 parm
->linelen
= parm
->readpos
= 0;
286 /* If the caller want to read multiple PEM objects from one
287 file, we have to reset our internal state and return a
288 EOF immediately. The caller is the expected to use
289 ksba_reader_clear to clear the EOF condition and continue
290 to read. If we don't want to do that we just return 0
291 bytes which will force the ksba_reader to skip until
293 if (parm
->allow_multi_pem
)
295 parm
->identified
= 0;
296 parm
->autodetect
= 0;
297 parm
->assume_pem
= 1;
299 return -1; /* Send EOF now. */
302 else if (parm
->stop_seen
)
303 { /* skip the rest of the line */
304 parm
->linelen
= parm
->readpos
= 0;
308 int idx
= parm
->base64
.idx
;
309 unsigned char val
= parm
->base64
.val
;
311 while (n
< count
&& parm
->readpos
< parm
->linelen
)
313 c
= parm
->line
[parm
->readpos
++];
314 if (c
== '\n' || c
== ' ' || c
== '\r' || c
== '\t')
317 { /* pad character: stop */
323 if( (c
= asctobin
[(c2
=c
)]) == 255 )
325 log_error (_("invalid radix64 character %02x skipped\n"),
351 if (parm
->readpos
== parm
->linelen
)
352 parm
->linelen
= parm
->readpos
= 0;
354 parm
->base64
.idx
= idx
;
355 parm
->base64
.val
= val
;
360 while (n
< count
&& parm
->readpos
< parm
->linelen
)
361 buffer
[n
++] = parm
->line
[parm
->readpos
++];
362 if (parm
->readpos
== parm
->linelen
)
363 parm
->linelen
= parm
->readpos
= 0;
373 simple_reader_cb (void *cb_value
, char *buffer
, size_t count
, size_t *nread
)
375 struct reader_cb_parm_s
*parm
= cb_value
;
381 return -1; /* not supported */
383 for (n
=0; n
< count
; n
++)
389 if ( ferror (parm
->fp
) )
392 break; /* return what we have before an EOF */
395 *(byte
*)buffer
++ = c
;
405 /* Call either es_putc or the plain putc. */
407 do_putc (int value
, FILE *fp
, estream_t stream
)
410 es_putc (value
, stream
);
415 /* Call either es_fputs or the plain fputs. */
417 do_fputs (const char *string
, FILE *fp
, estream_t stream
)
420 es_fputs (string
, stream
);
427 base64_writer_cb (void *cb_value
, const void *buffer
, size_t count
)
429 struct writer_cb_parm_s
*parm
= cb_value
;
430 unsigned char radbuf
[4];
431 int i
, c
, idx
, quad_count
;
432 const unsigned char *p
;
434 estream_t stream
= parm
->stream
;
439 if (!parm
->wrote_begin
)
443 do_fputs ("-----BEGIN ", fp
, stream
);
444 do_fputs (parm
->pem_name
, fp
, stream
);
445 do_fputs ("-----\n", fp
, stream
);
447 parm
->wrote_begin
= 1;
448 parm
->base64
.idx
= 0;
449 parm
->base64
.quad_count
= 0;
452 idx
= parm
->base64
.idx
;
453 quad_count
= parm
->base64
.quad_count
;
454 for (i
=0; i
< idx
; i
++)
455 radbuf
[i
] = parm
->base64
.radbuf
[i
];
457 for (p
=buffer
; count
; p
++, count
--)
463 c
= bintoasc
[(*radbuf
>> 2) & 077];
464 do_putc (c
, fp
, stream
);
465 c
= bintoasc
[(((*radbuf
<<4)&060)|((radbuf
[1] >> 4)&017))&077];
466 do_putc (c
, fp
, stream
);
467 c
= bintoasc
[(((radbuf
[1]<<2)&074)|((radbuf
[2]>>6)&03))&077];
468 do_putc (c
, fp
, stream
);
469 c
= bintoasc
[radbuf
[2]&077];
470 do_putc (c
, fp
, stream
);
471 if (++quad_count
>= (64/4))
473 do_fputs (LF
, fp
, stream
);
478 for (i
=0; i
< idx
; i
++)
479 parm
->base64
.radbuf
[i
] = radbuf
[i
];
480 parm
->base64
.idx
= idx
;
481 parm
->base64
.quad_count
= quad_count
;
483 return ((stream
? es_ferror (stream
) : ferror (fp
))
484 ? gpg_error_from_syserror ()
488 /* This callback is only used in stream mode. Hiowever, we don't
489 restrict it to this. */
491 plain_writer_cb (void *cb_value
, const void *buffer
, size_t count
)
493 struct writer_cb_parm_s
*parm
= cb_value
;
495 estream_t stream
= parm
->stream
;
501 es_write (stream
, buffer
, count
, NULL
);
503 fwrite (buffer
, count
, 1, fp
);
505 return ((stream
? es_ferror (stream
) : ferror (fp
))
506 ? gpg_error_from_syserror ()
511 base64_finish_write (struct writer_cb_parm_s
*parm
)
513 unsigned char radbuf
[4];
514 int i
, c
, idx
, quad_count
;
516 estream_t stream
= parm
->stream
;
518 if (!parm
->wrote_begin
)
519 return 0; /* Nothing written or we are not called in base-64 mode. */
521 /* flush the base64 encoding */
522 idx
= parm
->base64
.idx
;
523 quad_count
= parm
->base64
.quad_count
;
524 for (i
=0; i
< idx
; i
++)
525 radbuf
[i
] = parm
->base64
.radbuf
[i
];
529 c
= bintoasc
[(*radbuf
>>2)&077];
530 do_putc (c
, fp
, stream
);
533 c
= bintoasc
[((*radbuf
<< 4) & 060) & 077];
534 do_putc (c
, fp
, stream
);
535 do_putc ('=', fp
, stream
);
536 do_putc ('=', fp
, stream
);
540 c
= bintoasc
[(((*radbuf
<<4)&060)|((radbuf
[1]>>4)&017))&077];
541 do_putc (c
, fp
, stream
);
542 c
= bintoasc
[((radbuf
[1] << 2) & 074) & 077];
543 do_putc (c
, fp
, stream
);
544 do_putc ('=', fp
, stream
);
547 if (++quad_count
>= (64/4))
549 do_fputs (LF
, fp
, stream
);
555 do_fputs (LF
, fp
, stream
);
559 do_fputs ("-----END ", fp
, stream
);
560 do_fputs (parm
->pem_name
, fp
, stream
);
561 do_fputs ("-----\n", fp
, stream
);
564 return ((stream
? es_ferror (stream
) : ferror (fp
))
565 ? gpg_error_from_syserror ()
572 /* Create a reader for the given file descriptor. Depending on the
573 control information an input decoding is automagically choosen.
574 The function returns a Base64Context object which must be passed to
575 the gpgme_destroy_reader function. The created KsbaReader object
576 is also returned, but the caller must not call the
577 ksba_reader_release function on. If ALLOW_MULTI_PEM is true, the
578 reader expects that the caller uses ksba_reader_clear after EOF
579 until no more objects were found. */
581 gpgsm_create_reader (Base64Context
*ctx
,
582 ctrl_t ctrl
, FILE *fp
, int allow_multi_pem
,
583 ksba_reader_t
*r_reader
)
589 *ctx
= xtrycalloc (1, sizeof **ctx
);
591 return out_of_core ();
592 (*ctx
)->u
.rparm
.allow_multi_pem
= allow_multi_pem
;
594 rc
= ksba_reader_new (&r
);
597 xfree (*ctx
); *ctx
= NULL
;
601 (*ctx
)->u
.rparm
.fp
= fp
;
604 (*ctx
)->u
.rparm
.assume_pem
= 1;
605 (*ctx
)->u
.rparm
.assume_base64
= 1;
606 rc
= ksba_reader_set_cb (r
, base64_reader_cb
, &(*ctx
)->u
.rparm
);
608 else if (ctrl
->is_base64
)
610 (*ctx
)->u
.rparm
.assume_base64
= 1;
611 rc
= ksba_reader_set_cb (r
, base64_reader_cb
, &(*ctx
)->u
.rparm
);
613 else if (ctrl
->autodetect_encoding
)
615 (*ctx
)->u
.rparm
.autodetect
= 1;
616 rc
= ksba_reader_set_cb (r
, base64_reader_cb
, &(*ctx
)->u
.rparm
);
619 rc
= ksba_reader_set_cb (r
, simple_reader_cb
, &(*ctx
)->u
.rparm
);
623 ksba_reader_release (r
);
624 xfree (*ctx
); *ctx
= NULL
;
628 (*ctx
)->u2
.reader
= r
;
635 gpgsm_reader_eof_seen (Base64Context ctx
)
637 return ctx
&& ctx
->u
.rparm
.eof_seen
;
641 gpgsm_destroy_reader (Base64Context ctx
)
646 ksba_reader_release (ctx
->u2
.reader
);
652 /* Create a writer for the given stream FP or STREAM. Depending on
653 the control information an output encoding is automagically
654 choosen. The function returns a Base64Context object which must be
655 passed to the gpgme_destroy_writer function. The created
656 KsbaWriter object is also returned, but the caller must not call
657 the ksba_reader_release function on. */
659 gpgsm_create_writer (Base64Context
*ctx
,
660 ctrl_t ctrl
, FILE *fp
, estream_t stream
,
661 ksba_writer_t
*r_writer
)
667 *ctx
= xtrycalloc (1, sizeof **ctx
);
669 return out_of_core ();
671 rc
= ksba_writer_new (&w
);
674 xfree (*ctx
); *ctx
= NULL
;
678 if (ctrl
->create_pem
|| ctrl
->create_base64
)
680 (*ctx
)->u
.wparm
.fp
= fp
;
681 (*ctx
)->u
.wparm
.stream
= stream
;
682 if (ctrl
->create_pem
)
683 (*ctx
)->u
.wparm
.pem_name
= ctrl
->pem_name
? ctrl
->pem_name
685 rc
= ksba_writer_set_cb (w
, base64_writer_cb
, &(*ctx
)->u
.wparm
);
689 (*ctx
)->u
.wparm
.fp
= fp
;
690 (*ctx
)->u
.wparm
.stream
= stream
;
691 rc
= ksba_writer_set_cb (w
, plain_writer_cb
, &(*ctx
)->u
.wparm
);
694 rc
= ksba_writer_set_file (w
, fp
);
698 ksba_writer_release (w
);
699 xfree (*ctx
); *ctx
= NULL
;
703 (*ctx
)->u2
.writer
= w
;
710 gpgsm_finish_writer (Base64Context ctx
)
712 struct writer_cb_parm_s
*parm
;
715 return gpg_error (GPG_ERR_INV_VALUE
);
716 parm
= &ctx
->u
.wparm
;
717 if (parm
->did_finish
)
718 return 0; /* Already done. */
719 parm
->did_finish
= 1;
720 if (!parm
->fp
&& !parm
->stream
)
721 return 0; /* Callback was not used. */
722 return base64_finish_write (parm
);
726 gpgsm_destroy_writer (Base64Context ctx
)
731 ksba_writer_release (ctx
->u2
.writer
);