* gpgsm.c (main): New options --assume-{armor,base64,binary}.
[gnupg.git] / sm / base64.c
1 /* base64.c 
2  *      Copyright (C) 2001 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 2 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h> 
27 #include <time.h>
28 #include <assert.h>
29
30 #include <ksba.h>
31
32 #include "gpgsm.h"
33 #include "i18n.h"
34
35 #ifdef HAVE_DOSISH_SYSTEM
36   #define LF "\r\n"
37 #else
38   #define LF "\n"
39 #endif
40
41 /* data used by the reader callbacks */
42 struct reader_cb_parm_s {
43   FILE *fp;
44   unsigned char line[1024];
45   int linelen;
46   int readpos;
47   int have_lf;
48   unsigned long line_counter;
49
50   int autodetect; /* try to detect the input encoding */
51   int assume_pem; /* assume input encoding is PEM */
52   int assume_base64; /* assume inpout is base64 encoded */
53
54   int identified;
55   int is_pem;
56   int is_base64;
57   int stop_seen;
58
59   struct {
60     int idx;
61     unsigned char val;
62     int stop_seen;
63   } base64;
64 };
65
66 /* data used by the writer callbacks */
67 struct writer_cb_parm_s {
68   FILE *fp;
69   const char *pem_name;
70   
71   int wrote_begin;
72   int did_finish;
73
74   struct {
75     int idx;
76     int quad_count;
77     unsigned char radbuf[4];
78   } base64;
79
80 };
81
82
83 /* context for this module's functions */
84 struct base64_context_s {
85   union {
86     struct reader_cb_parm_s rparm;
87     struct writer_cb_parm_s wparm;
88   } u;
89 };
90
91
92 /* The base-64 character list */
93 static unsigned char bintoasc[64] = 
94        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
95        "abcdefghijklmnopqrstuvwxyz" 
96        "0123456789+/"; 
97 /* The reverse base-64 list */
98 static unsigned char asctobin[256] = {
99   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
100   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
101   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
102   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, 
103   0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, 
104   0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 
105   0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 
106   0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 
107   0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 
108   0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 
109   0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
110   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
111   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
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, 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
121 };
122
123
124
125 static int
126 base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
127 {
128   struct reader_cb_parm_s *parm = cb_value;
129   size_t n;
130   int c, c2;
131
132   *nread = 0;
133   if (!buffer)
134     return -1; /* not supported */
135
136  next:
137   if (!parm->linelen)
138     {
139       /* read an entire line or up to the size of the buffer */
140       parm->line_counter++;
141       parm->have_lf = 0;
142       for (n=0; n < DIM(parm->line);)
143         {
144           c = getc (parm->fp);
145           if (c == EOF)
146             {
147               if (ferror (parm->fp))
148                 return -1;
149               break; 
150             }
151           parm->line[n++] = c;
152           if (c == '\n')
153             {
154               parm->have_lf = 1;
155               /* FIXME: we need to skip overlong lines while detecting
156                  the dashed lines */
157               break;
158             }
159         }
160       parm->linelen = n;
161       if (!n)
162         return -1; /* eof */
163       parm->readpos = 0;
164     }
165
166   if (!parm->identified)
167     {
168       if (!parm->autodetect)
169         {
170           if (parm->assume_pem)
171             {
172               /* wait for the header line */
173               if (!parm->have_lf || strncmp (parm->line, "-----BEGIN ", 11)
174                   || strncmp (parm->line+11, "PGP ", 4))
175                 goto next;
176               parm->linelen = parm->readpos = 0;
177               parm->is_pem = 1;
178             }
179           else if (parm->assume_base64)
180             parm->is_base64 = 1;
181         }
182       else if (parm->line_counter == 1 && !parm->have_lf)
183         {
184           /* first line too long - assume DER encoding */
185           parm->is_pem = 0;
186         }
187       else if (parm->line_counter == 1 && parm->linelen && *parm->line == 0x30)
188         {
189           /* the very first byte does pretty much look like a SEQUENCE tag*/
190           parm->is_pem = 0;
191         }
192       else if ( parm->have_lf && !strncmp (parm->line, "-----BEGIN ", 11)
193                 && strncmp (parm->line+11, "PGP ", 4) )
194         {
195           /* Fixme: we must only compare if the line really starts at
196              the beginning */
197           parm->is_pem = 1;
198           parm->linelen = parm->readpos = 0;
199         }
200       else
201         {
202           parm->linelen = parm->readpos = 0;
203           goto next;
204         }
205       parm->identified = 1;
206       parm->base64.stop_seen = 0;
207       parm->base64.idx = 0;
208     }
209   
210
211   n = 0;
212   if (parm->is_pem || parm->is_base64)
213     {  
214       if (parm->is_pem && parm->have_lf
215           && !strncmp (parm->line, "-----END ", 9))
216         { 
217           parm->identified = 0;
218           parm->linelen = parm->readpos = 0;
219           /* let us return 0 */
220         }
221       else if (parm->stop_seen)
222         { /* skip the rest of the line */
223           parm->linelen = parm->readpos = 0;
224         }
225       else
226         {
227           int idx = parm->base64.idx;
228           unsigned char val = parm->base64.val;
229
230           while (n < count && parm->readpos < parm->linelen )
231             {
232               c = parm->line[parm->readpos++];
233               if (c == '\n' || c == ' ' || c == '\r' || c == '\t')
234                 continue;
235               if (c == '=')
236                 { /* pad character: stop */
237                   if (idx == 1)
238                     buffer[n++] = val; 
239                   parm->stop_seen = 1;
240                   break;
241                 }
242               if( (c = asctobin[(c2=c)]) == 255 ) 
243                 {
244                   log_error (_("invalid radix64 character %02x skipped\n"),
245                              c2);
246                   continue;
247                 }
248               switch (idx) 
249                 {
250                 case 0: 
251                   val = c << 2;
252                   break;
253                 case 1: 
254                   val |= (c>>4)&3;
255                   buffer[n++] = val;
256                   val = (c<<4)&0xf0;
257                   break;
258                 case 2: 
259                   val |= (c>>2)&15;
260                   buffer[n++] = val;
261                   val = (c<<6)&0xc0;
262                   break;
263                 case 3: 
264                   val |= c&0x3f;
265                   buffer[n++] = val;
266                   break;
267                 }
268               idx = (idx+1) % 4;
269             }
270           if (parm->readpos == parm->linelen)
271             parm->linelen = parm->readpos = 0;
272
273           parm->base64.idx = idx;
274           parm->base64.val = val;
275         }
276     }
277   else
278     { /* DER encoded */
279       while (n < count && parm->readpos < parm->linelen)
280           buffer[n++] = parm->line[parm->readpos++];
281       if (parm->readpos == parm->linelen)
282         parm->linelen = parm->readpos = 0;
283     }
284
285   *nread = n;
286   return 0;
287 }
288
289
290
291 static int
292 simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
293 {
294   struct reader_cb_parm_s *parm = cb_value;
295   size_t n;
296   int c = 0;
297
298   *nread = 0;
299   if (!buffer)
300     return -1; /* not supported */
301
302   for (n=0; n < count; n++)
303     {
304       c = getc (parm->fp);
305       if (c == EOF)
306         {
307           if ( ferror (parm->fp) )
308             return -1;
309           if (n)
310             break; /* return what we have before an EOF */
311           return -1;
312         }
313       *(byte *)buffer++ = c;
314     }
315
316   *nread = n;
317   return 0;
318 }
319
320
321
322 \f
323 static int
324 base64_writer_cb (void *cb_value, const void *buffer, size_t count)
325 {
326   struct writer_cb_parm_s *parm = cb_value;
327   unsigned char radbuf[4];
328   int i, c, idx, quad_count;
329   const unsigned char *p;
330   FILE *fp = parm->fp;
331
332   if (!count)
333     return 0;
334
335   if (!parm->wrote_begin)
336     {
337       if (parm->pem_name)
338         {
339           fputs ("-----BEGIN ", fp);
340           fputs (parm->pem_name, fp);
341           fputs ("-----\n", fp);
342         }
343       parm->wrote_begin = 1;
344       parm->base64.idx = 0;
345       parm->base64.quad_count = 0;
346     }
347
348   idx = parm->base64.idx;
349   quad_count = parm->base64.quad_count;
350   for (i=0; i < idx; i++)
351     radbuf[i] = parm->base64.radbuf[i];
352
353   for (p=buffer; count; p++, count--)
354     {
355       radbuf[idx++] = *p;
356       if (idx > 2)
357         {
358           idx = 0;
359           c = bintoasc[(*radbuf >> 2) & 077];
360           putc (c, fp);
361           c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
362           putc (c, fp);
363           c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
364           putc (c, fp);
365           c = bintoasc[radbuf[2]&077];
366           putc (c, fp);
367           if (++quad_count >= (64/4)) 
368             {
369               fputs (LF, fp);
370               quad_count = 0;
371             }
372         }
373     }
374   for (i=0; i < idx; i++)
375     parm->base64.radbuf[i] = radbuf[i];
376   parm->base64.idx = idx;
377   parm->base64.quad_count = quad_count;
378
379   return ferror (fp) ? KSBA_Write_Error:0;
380 }
381
382 static int
383 base64_finish_write (struct writer_cb_parm_s *parm)
384 {
385   unsigned char radbuf[4];
386   int i, c, idx, quad_count;
387   FILE *fp = parm->fp;
388
389   if (!parm->wrote_begin)
390     return 0; /* nothing written */
391
392   /* flush the base64 encoding */
393   idx = parm->base64.idx;
394   quad_count = parm->base64.quad_count;
395   for (i=0; i < idx; i++)
396     radbuf[i] = parm->base64.radbuf[i];
397
398   if (idx)
399     {
400       c = bintoasc[(*radbuf>>2)&077];
401       putc (c, fp);
402       if (idx == 1)
403         {
404           c = bintoasc[((*radbuf << 4) & 060) & 077];
405           putc (c, fp);
406           putc ('=', fp);
407           putc ('=', fp);
408         }
409       else 
410         { 
411           c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
412           putc (c, fp);
413           c = bintoasc[((radbuf[1] << 2) & 074) & 077];
414           putc (c, fp);
415           putc ('=', fp);
416
417         }
418       if (++quad_count >= (64/4)) 
419         {
420           fputs (LF, fp);
421           quad_count = 0;
422         }
423     }
424
425   if (quad_count)
426     fputs (LF, fp);
427
428   if (parm->pem_name)
429     {
430       fputs ("-----END ", fp);
431       fputs (parm->pem_name, fp);
432       fputs ("-----\n", fp);
433     }
434   return ferror (fp)? GNUPG_Write_Error : 0;
435 }
436
437
438
439 \f
440 /* Create a reader for the given file descriptor.  Depending on the
441    control information an input decoding is automagically choosen.
442    The function returns a Base64Context object which must be passed to
443    the gpgme_destroy_reader function.  The created KsbaReader object
444    is also returned, but the caller must not call the
445    ksba_reader_release function on. */
446 int
447 gpgsm_create_reader (Base64Context *ctx,
448                      CTRL ctrl, FILE *fp, KsbaReader *r_reader)
449 {
450   int rc;
451   KsbaReader r;
452
453   *r_reader = NULL;
454   *ctx = xtrycalloc (1, sizeof **ctx);
455   if (!*ctx)
456     return seterr (Out_Of_Core);
457
458   r = ksba_reader_new ();
459   if (!r)
460     {
461       xfree (*ctx); *ctx = NULL;
462       return seterr (Out_Of_Core);
463     }
464
465   (*ctx)->u.rparm.fp = fp;
466   if (ctrl->is_pem)
467     {
468       (*ctx)->u.rparm.assume_pem = 1;
469       (*ctx)->u.rparm.assume_base64 = 1;
470       rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
471     }
472   else if (ctrl->is_base64)
473     {
474       (*ctx)->u.rparm.assume_base64 = 1;
475       rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
476     }
477   else if (ctrl->autodetect_encoding)
478     {
479       (*ctx)->u.rparm.autodetect = 1;
480       rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
481     }
482   else
483       rc = ksba_reader_set_cb (r, simple_reader_cb, &(*ctx)->u.rparm);
484
485   if (rc)
486     {
487       ksba_reader_release (r);
488       xfree (*ctx); *ctx = NULL;
489       return map_ksba_err (rc);
490     }
491
492   *r_reader = r;
493   return 0;
494 }
495
496
497 void
498 gpgsm_destroy_reader (Base64Context ctx)
499 {
500   xfree (ctx);
501 }
502
503
504 \f
505 /* Create a writer for the given stream.  Depending on the control
506    information an output encoding is automagically choosen.  The
507    function returns a Base64Context object which must be passed to the
508    gpgme_destroy_writer function.  The created KsbaWriter object is
509    also returned, but the caller must not call the ksba_reader_release
510    function on. */
511 int
512 gpgsm_create_writer (Base64Context *ctx,
513                      CTRL ctrl, FILE *fp, KsbaWriter *r_writer)
514 {
515   int rc;
516   KsbaWriter w;
517
518   *r_writer = NULL;
519   *ctx = xtrycalloc (1, sizeof **ctx);
520   if (!*ctx)
521     return seterr (Out_Of_Core);
522
523   w = ksba_writer_new ();
524   if (!w)
525     {
526       xfree (*ctx); *ctx = NULL;
527       return seterr (Out_Of_Core);
528     }
529
530   if (ctrl->create_pem || ctrl->create_base64)
531     {
532       (*ctx)->u.wparm.fp = fp;
533       (*ctx)->u.wparm.pem_name = "CMS OBJECT"; /* fixme */
534       rc = ksba_writer_set_cb (w, base64_writer_cb, &(*ctx)->u.wparm);
535     }
536   else
537     rc = ksba_writer_set_file (w, fp);
538
539   if (rc)
540     {
541       ksba_writer_release (w);
542       xfree (*ctx); *ctx = NULL;
543       return map_ksba_err (rc);
544     }
545
546   *r_writer = w;
547   return 0;
548 }
549
550
551 int
552 gpgsm_finish_writer (Base64Context ctx)
553 {
554   struct writer_cb_parm_s *parm;
555   
556   if (!ctx)
557     return GNUPG_Invalid_Value;
558   parm = &ctx->u.wparm;
559   if (parm->did_finish)
560     return 0; /* already done */
561   parm->did_finish = 1;
562   if (!parm->fp)
563     return 0; /* callback was not used */
564   return base64_finish_write (parm);
565 }
566
567 void
568 gpgsm_destroy_writer (Base64Context ctx)
569 {
570   xfree (ctx);
571 }