2006-09-06 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / sm / base64.c
blob1d54567887884e311ca8fd50dbf0b40f46afca9c
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 2 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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19 * USA.
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <time.h>
29 #include <assert.h>
31 #include "gpgsm.h"
33 #include <ksba.h>
35 #include "i18n.h"
37 #ifdef HAVE_DOSISH_SYSTEM
38 #define LF "\r\n"
39 #else
40 #define LF "\n"
41 #endif
43 /* data used by the reader callbacks */
44 struct reader_cb_parm_s {
45 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;
75 const char *pem_name;
77 int wrote_begin;
78 int did_finish;
80 struct {
81 int idx;
82 int quad_count;
83 unsigned char radbuf[4];
84 } base64;
89 /* context for this module's functions */
90 struct base64_context_s {
91 union {
92 struct reader_cb_parm_s rparm;
93 struct writer_cb_parm_s wparm;
94 } u;
98 /* The base-64 character list */
99 static char bintoasc[64] =
100 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
101 "abcdefghijklmnopqrstuvwxyz"
102 "0123456789+/";
103 /* The reverse base-64 list */
104 static unsigned char asctobin[256] = {
105 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
106 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
107 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
108 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
109 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
110 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
111 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
112 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
113 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
114 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
115 0x31, 0x32, 0x33, 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, 0xff, 0xff, 0xff, 0xff, 0xff,
118 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
119 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
120 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
121 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
122 0xff, 0xff, 0xff, 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
130 static int
131 has_only_base64 (const unsigned char *line, int linelen)
133 if (linelen < 20)
134 return 0;
135 for (; linelen; line++, linelen--)
137 if (*line == '\n' || (linelen > 1 && *line == '\r' && line[1] == '\n'))
138 break;
139 if ( !strchr (bintoasc, *line) )
140 return 0;
142 return 1; /* yes */
145 static int
146 is_empty_line (const unsigned char *line, int linelen)
148 if (linelen >= 2 && *line == '\r' && line[1] == '\n')
149 return 1;
150 if (linelen >= 1 && *line == '\n')
151 return 1;
152 return 0;
156 static int
157 base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
159 struct reader_cb_parm_s *parm = cb_value;
160 size_t n;
161 int c, c2;
163 *nread = 0;
164 if (!buffer)
165 return -1; /* not supported */
167 next:
168 if (!parm->linelen)
170 /* read an entire line or up to the size of the buffer */
171 parm->line_counter++;
172 parm->have_lf = 0;
173 for (n=0; n < DIM(parm->line);)
175 c = getc (parm->fp);
176 if (c == EOF)
178 parm->eof_seen = 1;
179 if (ferror (parm->fp))
180 return -1;
181 break;
183 parm->line[n++] = c;
184 if (c == '\n')
186 parm->have_lf = 1;
187 /* Fixme: we need to skip overlong lines while detecting
188 the dashed lines */
189 break;
192 parm->linelen = n;
193 if (!n)
194 return -1; /* eof */
195 parm->readpos = 0;
198 if (!parm->identified)
200 if (!parm->autodetect)
202 if (parm->assume_pem)
204 /* wait for the header line */
205 parm->linelen = parm->readpos = 0;
206 if (!parm->have_lf
207 || strncmp ((char*)parm->line, "-----BEGIN ", 11)
208 || !strncmp ((char*)parm->line+11, "PGP ", 4))
209 goto next;
210 parm->is_pem = 1;
212 else if (parm->assume_base64)
213 parm->is_base64 = 1;
215 else if (parm->line_counter == 1 && !parm->have_lf)
217 /* first line too long - assume DER encoding */
218 parm->is_pem = 0;
220 else if (parm->line_counter == 1 && parm->linelen && *parm->line == 0x30)
222 /* the very first byte does pretty much look like a SEQUENCE tag*/
223 parm->is_pem = 0;
225 else if ( parm->have_lf
226 && !strncmp ((char*)parm->line, "-----BEGIN ", 11)
227 && strncmp ((char *)parm->line+11, "PGP ", 4) )
229 /* Fixme: we must only compare if the line really starts at
230 the beginning */
231 parm->is_pem = 1;
232 parm->linelen = parm->readpos = 0;
234 else if ( parm->have_lf && parm->line_counter == 1
235 && parm->linelen >= 13
236 && !ascii_memcasecmp (parm->line, "Content-Type:", 13))
237 { /* might be a S/MIME body */
238 parm->might_be_smime = 1;
239 parm->linelen = parm->readpos = 0;
240 goto next;
242 else if (parm->might_be_smime == 1
243 && is_empty_line (parm->line, parm->linelen))
245 parm->might_be_smime = 2;
246 parm->linelen = parm->readpos = 0;
247 goto next;
249 else if (parm->might_be_smime == 2)
251 parm->might_be_smime = 0;
252 if ( !has_only_base64 (parm->line, parm->linelen))
254 parm->linelen = parm->readpos = 0;
255 goto next;
257 parm->is_pem = 1;
259 else
261 parm->linelen = parm->readpos = 0;
262 goto next;
264 parm->identified = 1;
265 parm->base64.stop_seen = 0;
266 parm->base64.idx = 0;
270 n = 0;
271 if (parm->is_pem || parm->is_base64)
273 if (parm->is_pem && parm->have_lf
274 && !strncmp ((char*)parm->line, "-----END ", 9))
276 parm->identified = 0;
277 parm->linelen = parm->readpos = 0;
279 /* If the caller want to read multiple PEM objects from one
280 file, we have to reset our internal state and return a
281 EOF immediately. The caller is the expected to use
282 ksba_reader_clear to clear the EOF condition and continue
283 to read. If we don't want to do that we just return 0
284 bytes which will force the ksba_reader to skip until
285 EOF. */
286 if (parm->allow_multi_pem)
288 parm->identified = 0;
289 parm->autodetect = 0;
290 parm->assume_pem = 1;
291 parm->stop_seen = 0;
292 return -1; /* Send EOF now. */
295 else if (parm->stop_seen)
296 { /* skip the rest of the line */
297 parm->linelen = parm->readpos = 0;
299 else
301 int idx = parm->base64.idx;
302 unsigned char val = parm->base64.val;
304 while (n < count && parm->readpos < parm->linelen )
306 c = parm->line[parm->readpos++];
307 if (c == '\n' || c == ' ' || c == '\r' || c == '\t')
308 continue;
309 if (c == '=')
310 { /* pad character: stop */
311 if (idx == 1)
312 buffer[n++] = val;
313 parm->stop_seen = 1;
314 break;
316 if( (c = asctobin[(c2=c)]) == 255 )
318 log_error (_("invalid radix64 character %02x skipped\n"),
319 c2);
320 continue;
322 switch (idx)
324 case 0:
325 val = c << 2;
326 break;
327 case 1:
328 val |= (c>>4)&3;
329 buffer[n++] = val;
330 val = (c<<4)&0xf0;
331 break;
332 case 2:
333 val |= (c>>2)&15;
334 buffer[n++] = val;
335 val = (c<<6)&0xc0;
336 break;
337 case 3:
338 val |= c&0x3f;
339 buffer[n++] = val;
340 break;
342 idx = (idx+1) % 4;
344 if (parm->readpos == parm->linelen)
345 parm->linelen = parm->readpos = 0;
347 parm->base64.idx = idx;
348 parm->base64.val = val;
351 else
352 { /* DER encoded */
353 while (n < count && parm->readpos < parm->linelen)
354 buffer[n++] = parm->line[parm->readpos++];
355 if (parm->readpos == parm->linelen)
356 parm->linelen = parm->readpos = 0;
359 *nread = n;
360 return 0;
365 static int
366 simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
368 struct reader_cb_parm_s *parm = cb_value;
369 size_t n;
370 int c = 0;
372 *nread = 0;
373 if (!buffer)
374 return -1; /* not supported */
376 for (n=0; n < count; n++)
378 c = getc (parm->fp);
379 if (c == EOF)
381 parm->eof_seen = 1;
382 if ( ferror (parm->fp) )
383 return -1;
384 if (n)
385 break; /* return what we have before an EOF */
386 return -1;
388 *(byte *)buffer++ = c;
391 *nread = n;
392 return 0;
398 static int
399 base64_writer_cb (void *cb_value, const void *buffer, size_t count)
401 struct writer_cb_parm_s *parm = cb_value;
402 unsigned char radbuf[4];
403 int i, c, idx, quad_count;
404 const unsigned char *p;
405 FILE *fp = parm->fp;
407 if (!count)
408 return 0;
410 if (!parm->wrote_begin)
412 if (parm->pem_name)
414 fputs ("-----BEGIN ", fp);
415 fputs (parm->pem_name, fp);
416 fputs ("-----\n", fp);
418 parm->wrote_begin = 1;
419 parm->base64.idx = 0;
420 parm->base64.quad_count = 0;
423 idx = parm->base64.idx;
424 quad_count = parm->base64.quad_count;
425 for (i=0; i < idx; i++)
426 radbuf[i] = parm->base64.radbuf[i];
428 for (p=buffer; count; p++, count--)
430 radbuf[idx++] = *p;
431 if (idx > 2)
433 idx = 0;
434 c = bintoasc[(*radbuf >> 2) & 077];
435 putc (c, fp);
436 c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
437 putc (c, fp);
438 c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
439 putc (c, fp);
440 c = bintoasc[radbuf[2]&077];
441 putc (c, fp);
442 if (++quad_count >= (64/4))
444 fputs (LF, fp);
445 quad_count = 0;
449 for (i=0; i < idx; i++)
450 parm->base64.radbuf[i] = radbuf[i];
451 parm->base64.idx = idx;
452 parm->base64.quad_count = quad_count;
454 return ferror (fp) ? gpg_error_from_errno (errno) : 0;
457 static int
458 base64_finish_write (struct writer_cb_parm_s *parm)
460 unsigned char radbuf[4];
461 int i, c, idx, quad_count;
462 FILE *fp = parm->fp;
464 if (!parm->wrote_begin)
465 return 0; /* nothing written */
467 /* flush the base64 encoding */
468 idx = parm->base64.idx;
469 quad_count = parm->base64.quad_count;
470 for (i=0; i < idx; i++)
471 radbuf[i] = parm->base64.radbuf[i];
473 if (idx)
475 c = bintoasc[(*radbuf>>2)&077];
476 putc (c, fp);
477 if (idx == 1)
479 c = bintoasc[((*radbuf << 4) & 060) & 077];
480 putc (c, fp);
481 putc ('=', fp);
482 putc ('=', fp);
484 else
486 c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
487 putc (c, fp);
488 c = bintoasc[((radbuf[1] << 2) & 074) & 077];
489 putc (c, fp);
490 putc ('=', fp);
493 if (++quad_count >= (64/4))
495 fputs (LF, fp);
496 quad_count = 0;
500 if (quad_count)
501 fputs (LF, fp);
503 if (parm->pem_name)
505 fputs ("-----END ", fp);
506 fputs (parm->pem_name, fp);
507 fputs ("-----\n", fp);
509 return ferror (fp)? gpg_error (gpg_err_code_from_errno (errno)) : 0;
515 /* Create a reader for the given file descriptor. Depending on the
516 control information an input decoding is automagically choosen.
517 The function returns a Base64Context object which must be passed to
518 the gpgme_destroy_reader function. The created KsbaReader object
519 is also returned, but the caller must not call the
520 ksba_reader_release function on. If ALLOW_MULTI_PEM is true, the
521 reader expects that the caller uses ksba_reader_clear after EOF
522 until no more objects were found. */
524 gpgsm_create_reader (Base64Context *ctx,
525 ctrl_t ctrl, FILE *fp, int allow_multi_pem,
526 ksba_reader_t *r_reader)
528 int rc;
529 ksba_reader_t r;
531 *r_reader = NULL;
532 *ctx = xtrycalloc (1, sizeof **ctx);
533 if (!*ctx)
534 return out_of_core ();
535 (*ctx)->u.rparm.allow_multi_pem = allow_multi_pem;
537 rc = ksba_reader_new (&r);
538 if (rc)
540 xfree (*ctx); *ctx = NULL;
541 return rc;
544 (*ctx)->u.rparm.fp = fp;
545 if (ctrl->is_pem)
547 (*ctx)->u.rparm.assume_pem = 1;
548 (*ctx)->u.rparm.assume_base64 = 1;
549 rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
551 else if (ctrl->is_base64)
553 (*ctx)->u.rparm.assume_base64 = 1;
554 rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
556 else if (ctrl->autodetect_encoding)
558 (*ctx)->u.rparm.autodetect = 1;
559 rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
561 else
562 rc = ksba_reader_set_cb (r, simple_reader_cb, &(*ctx)->u.rparm);
564 if (rc)
566 ksba_reader_release (r);
567 xfree (*ctx); *ctx = NULL;
568 return rc;
571 *r_reader = r;
572 return 0;
577 gpgsm_reader_eof_seen (Base64Context ctx)
579 return ctx && ctx->u.rparm.eof_seen;
582 void
583 gpgsm_destroy_reader (Base64Context ctx)
585 xfree (ctx);
590 /* Create a writer for the given stream. Depending on the control
591 information an output encoding is automagically choosen. The
592 function returns a Base64Context object which must be passed to the
593 gpgme_destroy_writer function. The created KsbaWriter object is
594 also returned, but the caller must not call the ksba_reader_release
595 function on. */
597 gpgsm_create_writer (Base64Context *ctx,
598 ctrl_t ctrl, FILE *fp, ksba_writer_t *r_writer)
600 int rc;
601 ksba_writer_t w;
603 *r_writer = NULL;
604 *ctx = xtrycalloc (1, sizeof **ctx);
605 if (!*ctx)
606 return out_of_core ();
608 rc = ksba_writer_new (&w);
609 if (rc)
611 xfree (*ctx); *ctx = NULL;
612 return rc;
615 if (ctrl->create_pem || ctrl->create_base64)
617 (*ctx)->u.wparm.fp = fp;
618 if (ctrl->create_pem)
619 (*ctx)->u.wparm.pem_name = ctrl->pem_name? ctrl->pem_name
620 : "CMS OBJECT";
621 rc = ksba_writer_set_cb (w, base64_writer_cb, &(*ctx)->u.wparm);
623 else
624 rc = ksba_writer_set_file (w, fp);
626 if (rc)
628 ksba_writer_release (w);
629 xfree (*ctx); *ctx = NULL;
630 return rc;
633 *r_writer = w;
634 return 0;
639 gpgsm_finish_writer (Base64Context ctx)
641 struct writer_cb_parm_s *parm;
643 if (!ctx)
644 return gpg_error (GPG_ERR_INV_VALUE);
645 parm = &ctx->u.wparm;
646 if (parm->did_finish)
647 return 0; /* already done */
648 parm->did_finish = 1;
649 if (!parm->fp)
650 return 0; /* callback was not used */
651 return base64_finish_write (parm);
654 void
655 gpgsm_destroy_writer (Base64Context ctx)
657 xfree (ctx);