chiark / gitweb /
build: Enable gcc warnings to detect non-portable code.
[gnupg2.git] / sm / base64.c
1 /* base64.c
2  * Copyright (C) 2001, 2003, 2010 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
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>
28
29 #include "gpgsm.h"
30
31
32 #include <ksba.h>
33
34 #include "i18n.h"
35
36 #ifdef HAVE_DOSISH_SYSTEM
37   #define LF "\r\n"
38 #else
39   #define LF "\n"
40 #endif
41
42 /* Data used by the reader callbacks.  */
43 struct reader_cb_parm_s
44 {
45   estream_t fp;
46
47   unsigned char line[1024];
48   int linelen;
49   int readpos;
50   int have_lf;
51   unsigned long line_counter;
52
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. */
57
58   int identified;
59   int is_pem;
60   int is_base64;
61   int stop_seen;
62   int might_be_smime;
63
64   int eof_seen;
65
66   struct {
67     int idx;
68     unsigned char val;
69     int stop_seen;
70   } base64;
71 };
72
73
74 /* Data used by the writer callbacks.  */
75 struct writer_cb_parm_s
76 {
77   estream_t stream;    /* Output stream.  */
78
79   const char *pem_name;
80
81   int wrote_begin;
82   int did_finish;
83
84   struct {
85     int idx;
86     int quad_count;
87     unsigned char radbuf[4];
88   } base64;
89
90 };
91
92
93 /* context for this module's functions */
94 struct base64_context_s {
95   union {
96     struct reader_cb_parm_s rparm;
97     struct writer_cb_parm_s wparm;
98   } u;
99
100   union {
101     ksba_reader_t reader;
102     ksba_writer_t writer;
103   } u2;
104 };
105
106
107 /* The base-64 character list */
108 static char bintoasc[64] =
109        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
110        "abcdefghijklmnopqrstuvwxyz"
111        "0123456789+/";
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
136 };
137
138
139 static int
140 has_only_base64 (const unsigned char *line, int linelen)
141 {
142   if (linelen < 20)
143     return 0;
144   for (; linelen; line++, linelen--)
145     {
146       if (*line == '\n' || (linelen > 1 && *line == '\r' && line[1] == '\n'))
147           break;
148       if ( !strchr (bintoasc, *line) )
149         return 0;
150     }
151   return 1;  /* yes */
152 }
153
154 static int
155 is_empty_line (const unsigned char *line, int linelen)
156 {
157   if (linelen >= 2 && *line == '\r' && line[1] == '\n')
158     return 1;
159   if (linelen >= 1 && *line == '\n')
160     return 1;
161   return 0;
162 }
163
164
165 static int
166 base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
167 {
168   struct reader_cb_parm_s *parm = cb_value;
169   size_t n;
170   int c, c2;
171
172   *nread = 0;
173   if (!buffer)
174     return -1; /* not supported */
175
176  next:
177   if (!parm->linelen)
178     {
179       /* read an entire line or up to the size of the buffer */
180       parm->line_counter++;
181       parm->have_lf = 0;
182       for (n=0; n < DIM(parm->line);)
183         {
184           c = es_getc (parm->fp);
185           if (c == EOF)
186             {
187               parm->eof_seen = 1;
188               if (es_ferror (parm->fp))
189                 return -1;
190               break;
191             }
192           parm->line[n++] = c;
193           if (c == '\n')
194             {
195               parm->have_lf = 1;
196               /* Fixme: we need to skip overlong lines while detecting
197                  the dashed lines */
198               break;
199             }
200         }
201       parm->linelen = n;
202       if (!n)
203         return -1; /* eof */
204       parm->readpos = 0;
205     }
206
207   if (!parm->identified)
208     {
209       if (!parm->autodetect)
210         {
211           if (parm->assume_pem)
212             {
213               /* wait for the header line */
214               parm->linelen = parm->readpos = 0;
215               if (!parm->have_lf
216                   || strncmp ((char*)parm->line, "-----BEGIN ", 11)
217                   || !strncmp ((char*)parm->line+11, "PGP ", 4))
218                 goto next;
219               parm->is_pem = 1;
220             }
221           else if (parm->assume_base64)
222             parm->is_base64 = 1;
223         }
224       else if (parm->line_counter == 1 && !parm->have_lf)
225         {
226           /* first line too long - assume DER encoding */
227           parm->is_pem = 0;
228         }
229       else if (parm->line_counter == 1 && parm->linelen && *parm->line == 0x30)
230         {
231           /* the very first byte does pretty much look like a SEQUENCE tag*/
232           parm->is_pem = 0;
233         }
234       else if ( parm->have_lf
235                 && !strncmp ((char*)parm->line, "-----BEGIN ", 11)
236                 && strncmp ((char *)parm->line+11, "PGP ", 4) )
237         {
238           /* Fixme: we must only compare if the line really starts at
239              the beginning */
240           parm->is_pem = 1;
241           parm->linelen = parm->readpos = 0;
242         }
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;
249           goto next;
250         }
251       else if (parm->might_be_smime == 1
252                && is_empty_line (parm->line, parm->linelen))
253         {
254           parm->might_be_smime = 2;
255           parm->linelen = parm->readpos = 0;
256           goto next;
257         }
258       else if (parm->might_be_smime == 2)
259         {
260           parm->might_be_smime = 0;
261           if ( !has_only_base64 (parm->line, parm->linelen))
262             {
263               parm->linelen = parm->readpos = 0;
264               goto next;
265             }
266           parm->is_pem = 1;
267         }
268       else
269         {
270           parm->linelen = parm->readpos = 0;
271           goto next;
272         }
273       parm->identified = 1;
274       parm->base64.stop_seen = 0;
275       parm->base64.idx = 0;
276     }
277
278
279   n = 0;
280   if (parm->is_pem || parm->is_base64)
281     {
282       if (parm->is_pem && parm->have_lf
283           && !strncmp ((char*)parm->line, "-----END ", 9))
284         {
285           parm->identified = 0;
286           parm->linelen = parm->readpos = 0;
287
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
294              EOF. */
295           if (parm->allow_multi_pem)
296             {
297               parm->identified = 0;
298               parm->autodetect = 0;
299               parm->assume_pem = 1;
300               parm->stop_seen = 0;
301               return -1; /* Send EOF now. */
302             }
303         }
304       else if (parm->stop_seen)
305         { /* skip the rest of the line */
306           parm->linelen = parm->readpos = 0;
307         }
308       else
309         {
310           int idx = parm->base64.idx;
311           unsigned char val = parm->base64.val;
312
313           while (n < count && parm->readpos < parm->linelen )
314             {
315               c = parm->line[parm->readpos++];
316               if (c == '\n' || c == ' ' || c == '\r' || c == '\t')
317                 continue;
318               if (c == '=')
319                 { /* pad character: stop */
320                   if (idx == 1)
321                     buffer[n++] = val;
322                   parm->stop_seen = 1;
323                   break;
324                 }
325               if( (c = asctobin[(c2=c)]) == 255 )
326                 {
327                   log_error (_("invalid radix64 character %02x skipped\n"),
328                              c2);
329                   continue;
330                 }
331               switch (idx)
332                 {
333                 case 0:
334                   val = c << 2;
335                   break;
336                 case 1:
337                   val |= (c>>4)&3;
338                   buffer[n++] = val;
339                   val = (c<<4)&0xf0;
340                   break;
341                 case 2:
342                   val |= (c>>2)&15;
343                   buffer[n++] = val;
344                   val = (c<<6)&0xc0;
345                   break;
346                 case 3:
347                   val |= c&0x3f;
348                   buffer[n++] = val;
349                   break;
350                 }
351               idx = (idx+1) % 4;
352             }
353           if (parm->readpos == parm->linelen)
354             parm->linelen = parm->readpos = 0;
355
356           parm->base64.idx = idx;
357           parm->base64.val = val;
358         }
359     }
360   else
361     { /* DER encoded */
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;
366     }
367
368   *nread = n;
369   return 0;
370 }
371
372
373
374 static int
375 simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
376 {
377   struct reader_cb_parm_s *parm = cb_value;
378   size_t n;
379   int c = 0;
380
381   *nread = 0;
382   if (!buffer)
383     return -1; /* not supported */
384
385   for (n=0; n < count; n++)
386     {
387       c = es_getc (parm->fp);
388       if (c == EOF)
389         {
390           parm->eof_seen = 1;
391           if (es_ferror (parm->fp))
392             return -1;
393           if (n)
394             break; /* Return what we have before an EOF.  */
395           return -1;
396         }
397       *(byte *)buffer++ = c;
398     }
399
400   *nread = n;
401   return 0;
402 }
403
404
405
406 \f
407 static int
408 base64_writer_cb (void *cb_value, const void *buffer, size_t count)
409 {
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;
415
416   if (!count)
417     return 0;
418
419   if (!parm->wrote_begin)
420     {
421       if (parm->pem_name)
422         {
423           es_fputs ("-----BEGIN ", stream);
424           es_fputs (parm->pem_name, stream);
425           es_fputs ("-----\n", stream);
426         }
427       parm->wrote_begin = 1;
428       parm->base64.idx = 0;
429       parm->base64.quad_count = 0;
430     }
431
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];
436
437   for (p=buffer; count; p++, count--)
438     {
439       radbuf[idx++] = *p;
440       if (idx > 2)
441         {
442           idx = 0;
443           c = bintoasc[(*radbuf >> 2) & 077];
444           es_putc (c, stream);
445           c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
446           es_putc (c, stream);
447           c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
448           es_putc (c, stream);
449           c = bintoasc[radbuf[2]&077];
450           es_putc (c, stream);
451           if (++quad_count >= (64/4))
452             {
453               es_fputs (LF, stream);
454               quad_count = 0;
455             }
456         }
457     }
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;
462
463   return es_ferror (stream)? gpg_error_from_syserror () : 0;
464 }
465
466
467 /* This callback is only used in stream mode.  Hiowever, we don't
468    restrict it to this.  */
469 static int
470 plain_writer_cb (void *cb_value, const void *buffer, size_t count)
471 {
472   struct writer_cb_parm_s *parm = cb_value;
473   estream_t stream = parm->stream;
474
475   if (!count)
476     return 0;
477
478   es_write (stream, buffer, count, NULL);
479
480   return es_ferror (stream)? gpg_error_from_syserror () : 0;
481 }
482
483
484 static int
485 base64_finish_write (struct writer_cb_parm_s *parm)
486 {
487   unsigned char *radbuf;
488   int c, idx, quad_count;
489   estream_t stream = parm->stream;
490
491   if (!parm->wrote_begin)
492     return 0; /* Nothing written or we are not called in base-64 mode. */
493
494   /* flush the base64 encoding */
495   idx = parm->base64.idx;
496   quad_count = parm->base64.quad_count;
497   if (idx)
498     {
499       radbuf = parm->base64.radbuf;
500
501       c = bintoasc[(*radbuf>>2)&077];
502       es_putc (c, stream);
503       if (idx == 1)
504         {
505           c = bintoasc[((*radbuf << 4) & 060) & 077];
506           es_putc (c, stream);
507           es_putc ('=', stream);
508           es_putc ('=', stream);
509         }
510       else
511         {
512           c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
513           es_putc (c, stream);
514           c = bintoasc[((radbuf[1] << 2) & 074) & 077];
515           es_putc (c, stream);
516           es_putc ('=', stream);
517
518         }
519       if (++quad_count >= (64/4))
520         {
521           es_fputs (LF, stream);
522           quad_count = 0;
523         }
524     }
525
526   if (quad_count)
527     es_fputs (LF, stream);
528
529   if (parm->pem_name)
530     {
531       es_fputs ("-----END ", stream);
532       es_fputs (parm->pem_name, stream);
533       es_fputs ("-----\n", stream);
534     }
535
536   return es_ferror (stream)? gpg_error_from_syserror () : 0;
537 }
538
539
540
541 \f
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. */
550 int
551 gpgsm_create_reader (Base64Context *ctx,
552                      ctrl_t ctrl, estream_t fp, int allow_multi_pem,
553                      ksba_reader_t *r_reader)
554 {
555   int rc;
556   ksba_reader_t r;
557
558   *r_reader = NULL;
559   *ctx = xtrycalloc (1, sizeof **ctx);
560   if (!*ctx)
561     return out_of_core ();
562   (*ctx)->u.rparm.allow_multi_pem = allow_multi_pem;
563
564   rc = ksba_reader_new (&r);
565   if (rc)
566     {
567       xfree (*ctx); *ctx = NULL;
568       return rc;
569     }
570
571   (*ctx)->u.rparm.fp = fp;
572   if (ctrl->is_pem)
573     {
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);
577     }
578   else if (ctrl->is_base64)
579     {
580       (*ctx)->u.rparm.assume_base64 = 1;
581       rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
582     }
583   else if (ctrl->autodetect_encoding)
584     {
585       (*ctx)->u.rparm.autodetect = 1;
586       rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
587     }
588   else
589       rc = ksba_reader_set_cb (r, simple_reader_cb, &(*ctx)->u.rparm);
590
591   if (rc)
592     {
593       ksba_reader_release (r);
594       xfree (*ctx); *ctx = NULL;
595       return rc;
596     }
597
598   (*ctx)->u2.reader = r;
599   *r_reader = r;
600   return 0;
601 }
602
603
604 int
605 gpgsm_reader_eof_seen (Base64Context ctx)
606 {
607   return ctx && ctx->u.rparm.eof_seen;
608 }
609
610 void
611 gpgsm_destroy_reader (Base64Context ctx)
612 {
613   if (!ctx)
614     return;
615
616   ksba_reader_release (ctx->u2.reader);
617   xfree (ctx);
618 }
619
620
621 \f
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. */
628 int
629 gpgsm_create_writer (Base64Context *ctx, ctrl_t ctrl, estream_t stream,
630                      ksba_writer_t *r_writer)
631 {
632   int rc;
633   ksba_writer_t w;
634
635   *r_writer = NULL;
636   *ctx = xtrycalloc (1, sizeof **ctx);
637   if (!*ctx)
638     return out_of_core ();
639
640   rc = ksba_writer_new (&w);
641   if (rc)
642     {
643       xfree (*ctx); *ctx = NULL;
644       return rc;
645     }
646
647   if (ctrl->create_pem || ctrl->create_base64)
648     {
649       (*ctx)->u.wparm.stream = stream;
650       if (ctrl->create_pem)
651         (*ctx)->u.wparm.pem_name = ctrl->pem_name? ctrl->pem_name
652                                                  : "CMS OBJECT";
653       rc = ksba_writer_set_cb (w, base64_writer_cb, &(*ctx)->u.wparm);
654     }
655   else if (stream)
656     {
657       (*ctx)->u.wparm.stream = stream;
658       rc = ksba_writer_set_cb (w, plain_writer_cb, &(*ctx)->u.wparm);
659     }
660   else
661     rc = gpg_error (GPG_ERR_INV_ARG);
662
663   if (rc)
664     {
665       ksba_writer_release (w);
666       xfree (*ctx); *ctx = NULL;
667       return rc;
668     }
669
670   (*ctx)->u2.writer = w;
671   *r_writer = w;
672   return 0;
673 }
674
675
676 int
677 gpgsm_finish_writer (Base64Context ctx)
678 {
679   struct writer_cb_parm_s *parm;
680
681   if (!ctx)
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;
687   if (!parm->stream)
688     return 0; /* Callback was not used.  */
689   return base64_finish_write (parm);
690 }
691
692 void
693 gpgsm_destroy_writer (Base64Context ctx)
694 {
695   if (!ctx)
696     return;
697
698   ksba_writer_release (ctx->u2.writer);
699   xfree (ctx);
700 }