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