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