agent/
[gnupg.git] / sm / base64.c
blobb0c8dc8e8fa514344724fd9a4db0d5313510ce0c
1 /* base64.c
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/>.
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <time.h>
27 #include <assert.h>
29 #include "gpgsm.h"
32 #include <ksba.h>
34 #include "i18n.h"
36 #ifdef HAVE_DOSISH_SYSTEM
37 #define LF "\r\n"
38 #else
39 #define LF "\n"
40 #endif
42 /* data used by the reader callbacks */
43 struct reader_cb_parm_s {
44 FILE *fp;
46 unsigned char line[1024];
47 int linelen;
48 int readpos;
49 int have_lf;
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. */
57 int identified;
58 int is_pem;
59 int is_base64;
60 int stop_seen;
61 int might_be_smime;
63 int eof_seen;
65 struct {
66 int idx;
67 unsigned char val;
68 int stop_seen;
69 } base64;
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. */
77 const char *pem_name;
79 int wrote_begin;
80 int did_finish;
82 struct {
83 int idx;
84 int quad_count;
85 unsigned char radbuf[4];
86 } base64;
91 /* context for this module's functions */
92 struct base64_context_s {
93 union {
94 struct reader_cb_parm_s rparm;
95 struct writer_cb_parm_s wparm;
96 } u;
98 union {
99 ksba_reader_t reader;
100 ksba_writer_t writer;
101 } u2;
105 /* The base-64 character list */
106 static char bintoasc[64] =
107 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
108 "abcdefghijklmnopqrstuvwxyz"
109 "0123456789+/";
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
137 static int
138 has_only_base64 (const unsigned char *line, int linelen)
140 if (linelen < 20)
141 return 0;
142 for (; linelen; line++, linelen--)
144 if (*line == '\n' || (linelen > 1 && *line == '\r' && line[1] == '\n'))
145 break;
146 if ( !strchr (bintoasc, *line) )
147 return 0;
149 return 1; /* yes */
152 static int
153 is_empty_line (const unsigned char *line, int linelen)
155 if (linelen >= 2 && *line == '\r' && line[1] == '\n')
156 return 1;
157 if (linelen >= 1 && *line == '\n')
158 return 1;
159 return 0;
163 static int
164 base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
166 struct reader_cb_parm_s *parm = cb_value;
167 size_t n;
168 int c, c2;
170 *nread = 0;
171 if (!buffer)
172 return -1; /* not supported */
174 next:
175 if (!parm->linelen)
177 /* read an entire line or up to the size of the buffer */
178 parm->line_counter++;
179 parm->have_lf = 0;
180 for (n=0; n < DIM(parm->line);)
182 c = getc (parm->fp);
183 if (c == EOF)
185 parm->eof_seen = 1;
186 if (ferror (parm->fp))
187 return -1;
188 break;
190 parm->line[n++] = c;
191 if (c == '\n')
193 parm->have_lf = 1;
194 /* Fixme: we need to skip overlong lines while detecting
195 the dashed lines */
196 break;
199 parm->linelen = n;
200 if (!n)
201 return -1; /* eof */
202 parm->readpos = 0;
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;
213 if (!parm->have_lf
214 || strncmp ((char*)parm->line, "-----BEGIN ", 11)
215 || !strncmp ((char*)parm->line+11, "PGP ", 4))
216 goto next;
217 parm->is_pem = 1;
219 else if (parm->assume_base64)
220 parm->is_base64 = 1;
222 else if (parm->line_counter == 1 && !parm->have_lf)
224 /* first line too long - assume DER encoding */
225 parm->is_pem = 0;
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*/
230 parm->is_pem = 0;
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
237 the beginning */
238 parm->is_pem = 1;
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;
247 goto next;
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;
254 goto next;
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;
262 goto next;
264 parm->is_pem = 1;
266 else
268 parm->linelen = parm->readpos = 0;
269 goto next;
271 parm->identified = 1;
272 parm->base64.stop_seen = 0;
273 parm->base64.idx = 0;
277 n = 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
292 EOF. */
293 if (parm->allow_multi_pem)
295 parm->identified = 0;
296 parm->autodetect = 0;
297 parm->assume_pem = 1;
298 parm->stop_seen = 0;
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;
306 else
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')
315 continue;
316 if (c == '=')
317 { /* pad character: stop */
318 if (idx == 1)
319 buffer[n++] = val;
320 parm->stop_seen = 1;
321 break;
323 if( (c = asctobin[(c2=c)]) == 255 )
325 log_error (_("invalid radix64 character %02x skipped\n"),
326 c2);
327 continue;
329 switch (idx)
331 case 0:
332 val = c << 2;
333 break;
334 case 1:
335 val |= (c>>4)&3;
336 buffer[n++] = val;
337 val = (c<<4)&0xf0;
338 break;
339 case 2:
340 val |= (c>>2)&15;
341 buffer[n++] = val;
342 val = (c<<6)&0xc0;
343 break;
344 case 3:
345 val |= c&0x3f;
346 buffer[n++] = val;
347 break;
349 idx = (idx+1) % 4;
351 if (parm->readpos == parm->linelen)
352 parm->linelen = parm->readpos = 0;
354 parm->base64.idx = idx;
355 parm->base64.val = val;
358 else
359 { /* DER encoded */
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;
366 *nread = n;
367 return 0;
372 static int
373 simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
375 struct reader_cb_parm_s *parm = cb_value;
376 size_t n;
377 int c = 0;
379 *nread = 0;
380 if (!buffer)
381 return -1; /* not supported */
383 for (n=0; n < count; n++)
385 c = getc (parm->fp);
386 if (c == EOF)
388 parm->eof_seen = 1;
389 if ( ferror (parm->fp) )
390 return -1;
391 if (n)
392 break; /* return what we have before an EOF */
393 return -1;
395 *(byte *)buffer++ = c;
398 *nread = n;
399 return 0;
405 /* Call either es_putc or the plain putc. */
406 static void
407 do_putc (int value, FILE *fp, estream_t stream)
409 if (stream)
410 es_putc (value, stream);
411 else
412 putc (value, fp);
415 /* Call either es_fputs or the plain fputs. */
416 static void
417 do_fputs (const char *string, FILE *fp, estream_t stream)
419 if (stream)
420 es_fputs (string, stream);
421 else
422 fputs (string, fp);
426 static int
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;
433 FILE *fp = parm->fp;
434 estream_t stream = parm->stream;
436 if (!count)
437 return 0;
439 if (!parm->wrote_begin)
441 if (parm->pem_name)
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--)
459 radbuf[idx++] = *p;
460 if (idx > 2)
462 idx = 0;
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);
474 quad_count = 0;
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 ()
485 : 0);
488 /* This callback is only used in stream mode. Hiowever, we don't
489 restrict it to this. */
490 static int
491 plain_writer_cb (void *cb_value, const void *buffer, size_t count)
493 struct writer_cb_parm_s *parm = cb_value;
494 FILE *fp = parm->fp;
495 estream_t stream = parm->stream;
497 if (!count)
498 return 0;
500 if (stream)
501 es_write (stream, buffer, count, NULL);
502 else
503 fwrite (buffer, count, 1, fp);
505 return ((stream? es_ferror (stream) : ferror (fp))
506 ? gpg_error_from_syserror ()
507 : 0);
510 static int
511 base64_finish_write (struct writer_cb_parm_s *parm)
513 unsigned char radbuf[4];
514 int i, c, idx, quad_count;
515 FILE *fp = parm->fp;
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];
527 if (idx)
529 c = bintoasc[(*radbuf>>2)&077];
530 do_putc (c, fp, stream);
531 if (idx == 1)
533 c = bintoasc[((*radbuf << 4) & 060) & 077];
534 do_putc (c, fp, stream);
535 do_putc ('=', fp, stream);
536 do_putc ('=', fp, stream);
538 else
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);
550 quad_count = 0;
554 if (quad_count)
555 do_fputs (LF, fp, stream);
557 if (parm->pem_name)
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 ()
566 : 0);
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)
585 int rc;
586 ksba_reader_t r;
588 *r_reader = NULL;
589 *ctx = xtrycalloc (1, sizeof **ctx);
590 if (!*ctx)
591 return out_of_core ();
592 (*ctx)->u.rparm.allow_multi_pem = allow_multi_pem;
594 rc = ksba_reader_new (&r);
595 if (rc)
597 xfree (*ctx); *ctx = NULL;
598 return rc;
601 (*ctx)->u.rparm.fp = fp;
602 if (ctrl->is_pem)
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);
618 else
619 rc = ksba_reader_set_cb (r, simple_reader_cb, &(*ctx)->u.rparm);
621 if (rc)
623 ksba_reader_release (r);
624 xfree (*ctx); *ctx = NULL;
625 return rc;
628 (*ctx)->u2.reader = r;
629 *r_reader = r;
630 return 0;
635 gpgsm_reader_eof_seen (Base64Context ctx)
637 return ctx && ctx->u.rparm.eof_seen;
640 void
641 gpgsm_destroy_reader (Base64Context ctx)
643 if (!ctx)
644 return;
646 ksba_reader_release (ctx->u2.reader);
647 xfree (ctx);
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)
663 int rc;
664 ksba_writer_t w;
666 *r_writer = NULL;
667 *ctx = xtrycalloc (1, sizeof **ctx);
668 if (!*ctx)
669 return out_of_core ();
671 rc = ksba_writer_new (&w);
672 if (rc)
674 xfree (*ctx); *ctx = NULL;
675 return rc;
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
684 : "CMS OBJECT";
685 rc = ksba_writer_set_cb (w, base64_writer_cb, &(*ctx)->u.wparm);
687 else if (stream)
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);
693 else
694 rc = ksba_writer_set_file (w, fp);
696 if (rc)
698 ksba_writer_release (w);
699 xfree (*ctx); *ctx = NULL;
700 return rc;
703 (*ctx)->u2.writer = w;
704 *r_writer = w;
705 return 0;
710 gpgsm_finish_writer (Base64Context ctx)
712 struct writer_cb_parm_s *parm;
714 if (!ctx)
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);
725 void
726 gpgsm_destroy_writer (Base64Context ctx)
728 if (!ctx)
729 return;
731 ksba_writer_release (ctx->u2.writer);
732 xfree (ctx);