backup
[gnupg.git] / g10 / armor.c
1 /* armor.c - Armor filter
2  *      Copyright (C) 1998 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 <assert.h>
27
28 #include "errors.h"
29 #include "iobuf.h"
30 #include "memory.h"
31 #include "util.h"
32 #include "filter.h"
33 #include "packet.h"
34 #include "options.h"
35 #include "main.h"
36 #include "status.h"
37 #include "i18n.h"
38
39
40 #define CRCINIT 0xB704CE
41 #define CRCPOLY 0X864CFB
42 #define CRCUPDATE(a,c) do {                                                 \
43                         a = ((a) << 8) ^ crc_table[((a)&0xff >> 16) ^ (c)]; \
44                         a &= 0x00ffffff;                                    \
45                     } while(0)
46 static u32 crc_table[256];
47 static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
48                          "abcdefghijklmnopqrstuvwxyz"
49                          "0123456789+/";
50 static byte asctobin[256]; /* runtime initialized */
51 static int is_initialized;
52
53
54 typedef enum {
55     fhdrHASArmor = 0,
56     fhdrNOArmor,
57     fhdrINIT,
58     fhdrINITCont,
59     fhdrINITSkip,
60     fhdrCHECKBegin,
61     fhdrWAITHeader,
62     fhdrWAITClearsig,
63     fhdrSKIPHeader,
64     fhdrCLEARSIG,
65     fhdrREADClearsig,
66     fhdrNullClearsig,
67     fhdrEMPTYClearsig,
68     fhdrCHECKClearsig,
69     fhdrCHECKClearsig2,
70     fhdrCHECKDashEscaped,
71     fhdrCHECKDashEscaped2,
72     fhdrCHECKDashEscaped3,
73     fhdrREADClearsigNext,
74     fhdrENDClearsig,
75     fhdrENDClearsigHelp,
76     fhdrTESTSpaces,
77     fhdrTEXT,
78     fhdrERROR,
79     fhdrERRORShow,
80     fhdrEOF
81 } fhdr_state_t;
82
83
84 /* if we encounter this armor string with this index, go
85  * into a mode which fakes packets and wait for the next armor */
86 #define BEGIN_SIGNED_MSG_IDX 3
87 static char *head_strings[] = {
88     "BEGIN PGP MESSAGE",
89     "BEGIN PGP PUBLIC KEY BLOCK",
90     "BEGIN PGP SIGNATURE",
91     "BEGIN PGP SIGNED MESSAGE",
92     "BEGIN PGP ARMORED FILE",       /* gnupg extension */
93     "BEGIN PGP PRIVATE KEY BLOCK",
94     "BEGIN PGP SECRET KEY BLOCK",   /* only used by pgp2 */
95     NULL
96 };
97 static char *tail_strings[] = {
98     "END PGP MESSAGE",
99     "END PGP PUBLIC KEY BLOCK",
100     "END PGP SIGNATURE",
101     "END dummy",
102     "END PGP ARMORED FILE",
103     "END PGP PRIVATE KEY BLOCK",
104     "END PGP SECRET KEY BLOCK",
105     NULL
106 };
107
108
109 static fhdr_state_t find_header( fhdr_state_t state,
110                                  byte *buf, size_t *r_buflen,
111                                  IOBUF a, size_t n,
112                                  unsigned *r_empty, int *r_hashes );
113
114
115 static void
116 initialize(void)
117 {
118     int i, j;
119     u32 t;
120     byte *s;
121
122     /* init the crc lookup table */
123     crc_table[0] = 0;
124     for(i=j=0; j < 128; j++ ) {
125         t = crc_table[j];
126         if( t & 0x00800000 ) {
127             t <<= 1;
128             crc_table[i++] = t ^ CRCPOLY;
129             crc_table[i++] = t;
130         }
131         else {
132             t <<= 1;
133             crc_table[i++] = t;
134             crc_table[i++] = t ^ CRCPOLY;
135         }
136     }
137     /* build the helptable for radix64 to bin conversion */
138     for(i=0; i < 256; i++ )
139         asctobin[i] = 255; /* used to detect invalid characters */
140     for(s=bintoasc,i=0; *s; s++,i++ )
141         asctobin[*s] = i;
142
143     is_initialized=1;
144 }
145
146 /****************
147  * Check whether this is an armored file or not
148  * See also parse-packet.c for details on this code
149  * Returns: True if it seems to be armored
150  */
151 static int
152 is_armored( byte *buf )
153 {
154     int ctb, pkttype;
155
156     ctb = *buf;
157     if( !(ctb & 0x80) )
158         return 1; /* invalid packet: assume it is armored */
159     pkttype =  ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf);
160     switch( pkttype ) {
161       case PKT_MARKER:
162       case PKT_SYMKEY_ENC:
163       case PKT_PUBLIC_KEY:
164       case PKT_SECRET_KEY:
165       case PKT_PUBKEY_ENC:
166       case PKT_SIGNATURE:
167       case PKT_COMMENT:
168       case PKT_OLD_COMMENT:
169       case PKT_PLAINTEXT:
170       case PKT_COMPRESSED:
171       case PKT_ENCRYPTED:
172         return 0; /* seems to be a regular packet: not armored */
173     }
174
175     return 1;
176 }
177
178
179 /****************
180  * Try to check whether the iobuf is armored
181  * Returns true if this may be the case; the caller should use the
182  *         filter to do further processing.
183  */
184 int
185 use_armor_filter( IOBUF a )
186 {
187     byte buf[1];
188     int n;
189
190     n = iobuf_peek(a, buf, 1 );
191     if( n == -1 )
192         return 0; /* EOF, doesn't matter whether armored or not */
193     if( !n )
194         return 1; /* can't check it: try armored */
195     return is_armored(buf);
196 }
197
198
199
200
201 static void
202 invalid_armor(void)
203 {
204     write_status(STATUS_BADARMOR);
205     g10_exit(1); /* stop here */
206 }
207
208
209 /****************
210  * check whether the armor header is valid on a signed message.
211  * this is for security reasons: the header lines are not included in the
212  * hash and by using some creative formatting rules, Mallory could fake
213  * any text at the beginning of a document; assuming it is read with
214  * a simple viewer. We only allow the Hash Header.
215  */
216 static int
217 parse_hash_header( const char *line )
218 {
219     const char *s, *s2;
220     unsigned found = 0;
221
222     if( strlen(line) < 6  || strlen(line) > 60 )
223         return 0; /* too short or too long */
224     if( memcmp( line, "Hash:", 5 ) )
225         return 0; /* invalid header */
226     s = line+5;
227     for(s=line+5;;s=s2) {
228         for(; *s && (*s==' ' || *s == '\t'); s++ )
229             ;
230         if( !*s )
231             break;
232         for(s2=s+1; *s2 && *s2!=' ' && *s2 != '\t' && *s2 != ','; s2++ )
233             ;
234         if( !strncmp( s, "RIPEMD160", s2-s ) )
235             found |= 1;
236         else if( !strncmp( s, "SHA1", s2-s ) )
237             found |= 2;
238         else if( !strncmp( s, "MD5", s2-s ) )
239             found |= 4;
240         else if( !strncmp( s, "TIGER", s2-s ) )
241             found |= 8;
242         else
243             return 0;
244         for(; *s2 && (*s2==' ' || *s2 == '\t'); s2++ )
245             ;
246         if( *s2 && *s2 != ',' )
247             return 0;
248         if( *s2 )
249             s2++;
250     }
251     return found;
252 }
253
254
255 /****************
256  * parse an ascii armor.
257  * Returns: the state,
258  *          the remaining bytes in BUF are returned in RBUFLEN.
259  *          r_empty return the # of empty lines before the buffer
260  */
261 static fhdr_state_t
262 find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
263              IOBUF a, size_t n, unsigned *r_empty, int *r_hashes )
264 {
265     int c=0, i;
266     const char *s;
267     byte *p;
268     size_t buflen;
269     int cont;
270     int clearsig=0;
271     int hdr_line=0;
272     unsigned empty = 0;
273
274     buflen = *r_buflen;
275     assert(buflen >= 100 );
276     buflen -= 3; /* reserved room for CR,LF and one extra */
277
278     do {
279         switch( state ) {
280           case fhdrHASArmor:
281             /* read at least the first byte to check whether it is armored
282              * or not */
283             c = 0;
284             for(n=0; n < 28 && (c=iobuf_get2(a)) != -1 && c != '\n'; )
285                 buf[n++] = c;
286             if( !n && c == '\n' )
287                 state = fhdrCHECKBegin;
288             else if( !n  || c == -1 )
289                 state = fhdrNOArmor; /* too short */
290             else if( !is_armored( buf ) )
291                 state = fhdrNOArmor;
292             else if( c == '\n' )
293                 state = fhdrCHECKBegin;
294             else
295                 state = fhdrINITCont;
296             break;
297
298           case fhdrINIT: /* read some stuff into buffer */
299             n = 0;
300           case fhdrINITCont: /* read more stuff into buffer */
301             c = 0;
302             for(; n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n'; )
303                 buf[n++] = c;
304             state = c == '\n' ? fhdrCHECKBegin :
305                      c == -1  ? fhdrEOF : fhdrINITSkip;
306             break;
307
308           case fhdrINITSkip:
309             if( c == '\n' )
310                 n = 0;
311             else {
312                 while( (c=iobuf_get2(a)) != -1 && c != '\n' )
313                     ;
314             }
315             state =  c == -1? fhdrEOF : fhdrINIT;
316             break;
317
318           case fhdrSKIPHeader:
319             while( (c=iobuf_get2(a)) != -1 && c != '\n' )
320                 ;
321             state =  c == -1? fhdrEOF : fhdrWAITHeader;
322             break;
323
324           case fhdrWAITHeader: /* wait for Header lines */
325             c = 0;
326             for(n=0; n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n'; )
327                 buf[n++] = c;
328             buf[n] = 0;
329             if( n < buflen || c == '\n' ) {
330                 if( n && buf[0] != '\r') { /* maybe a header */
331                     if( strchr( buf, ':') ) { /* yes */
332                         int hashes=0;
333                         if( buf[n-1] == '\r' )
334                             buf[--n] = 0;
335                         if( opt.verbose ) {
336                             log_info(_("armor header: "));
337                             print_string( stderr, buf, n, 0 );
338                             putc('\n', stderr);
339                         }
340                         if( clearsig && !(hashes=parse_hash_header( buf )) ) {
341                             log_error(_("invalid clearsig header\n"));
342                             state = fhdrERROR;
343                         }
344                         else {
345                             state = fhdrWAITHeader;
346                             if( r_hashes )
347                                 *r_hashes |= hashes;
348                         }
349                     }
350                     else if( clearsig && n > 15 && !memcmp(buf, "-----", 5 ) )
351                         state = fhdrNullClearsig;
352                     else
353                         state = fhdrCHECKDashEscaped3;
354                 }
355                 else if( !n || (buf[0] == '\r' && !buf[1]) ) { /* empty line */
356                     if( clearsig )
357                         state = fhdrWAITClearsig;
358                     else {
359                         /* this is not really correct: if we do not have
360                          * a clearsig and no armor lines we are not allowed
361                          * to have an empty line */
362                         n = 0;
363                         state = fhdrTEXT;
364                     }
365                 }
366                 else {
367                     log_error(_("invalid armor header: "));
368                     print_string( stderr, buf, n, 0 );
369                     putc('\n', stderr);
370                     state = fhdrERROR;
371                 }
372             }
373             else if( c != -1 ) {
374                 if( strchr( buf, ':') ) { /* buffer to short, but this is okay*/
375                     if( opt.verbose ) {
376                         log_info(_("armor header: "));
377                         print_string( stderr, buf, n, 0 );
378                         fputs("[...]\n", stderr);  /* indicate it is truncated */
379                     }
380                     state = fhdrSKIPHeader;  /* skip rest of line */
381                 }
382                 else /* line too long */
383                     state = fhdrERROR;
384             }
385             else
386                 state = fhdrEOF;
387             break;
388
389           case fhdrWAITClearsig: /* skip the empty line (for clearsig) */
390             c = 0;
391             for(n=0; n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n'; )
392                 buf[n++] = c;
393             if( n < buflen || c == '\n' ) {
394                 buf[n] = 0;
395                 if( n > 15 && !memcmp(buf, "-----", 5 ) )
396                     state = fhdrNullClearsig;
397                 else
398                     state = fhdrCHECKDashEscaped3;
399             }
400             else {
401                 /* fixme: we should check whether this line continues
402                  *   it is possible that we have only read ws until here
403                  *   and more stuff is to come */
404                 state = fhdrEOF;
405             }
406             break;
407
408           case fhdrNullClearsig: /* zero length cleartext */
409             state = fhdrENDClearsig;
410             break;
411
412           case fhdrENDClearsig:
413           case fhdrCHECKBegin:
414             state = state == fhdrCHECKBegin ? fhdrINITSkip : fhdrERRORShow;
415             if( n < 15 )
416                 break;  /* too short */
417             if( memcmp( buf, "-----", 5 ) )
418                 break;
419             buf[n] = 0;
420             p = strstr(buf+5, "-----");
421             if( !p )
422                 break;
423             *p = 0;
424             p += 5;
425             if( *p == '\r' )
426                 p++;
427             if( *p )
428                 break; /* garbage after dashes */
429             p = buf+5;
430             for(i=0; (s=head_strings[i]); i++ )
431                 if( !strcmp(s, p) )
432                     break;
433             if( !s )
434                 break; /* unknown begin line */
435             /* found the begin line */
436             hdr_line = i;
437             state = fhdrWAITHeader;
438             if( hdr_line == BEGIN_SIGNED_MSG_IDX )
439                 clearsig = 1;
440             if( opt.verbose > 1 )
441                 log_info(_("armor: %s\n"), head_strings[hdr_line]);
442             break;
443
444           case fhdrCLEARSIG:
445           case fhdrEMPTYClearsig:
446           case fhdrREADClearsig:
447             /* we are at the start of a line: read a clearsig into the buffer
448              * we have to look for a header line or dashed escaped text*/
449             n = 0;
450             c = 0;
451             while( n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n' )
452                 buf[n++] = c;
453             buf[n] = 0;
454             if( c == -1 )
455                 state = fhdrEOF;
456             else if( !n || ( buf[0]=='\r' && !buf[1] ) ) {
457                 state = fhdrEMPTYClearsig;
458                 empty++;
459             }
460             else if( c == '\n' )
461                 state = fhdrCHECKClearsig2;
462             else
463                 state = fhdrCHECKClearsig;
464             break;
465
466           case fhdrCHECKDashEscaped3:
467             if( !(n > 1 && buf[0] == '-' && buf[1] == ' ' ) ) {
468                 state = fhdrTEXT;
469                 break;
470             }
471             /* fall through */
472           case fhdrCHECKDashEscaped2:
473           case fhdrCHECKDashEscaped:
474             /* check dash escaped line */
475             if( buf[2] == '-' || ( n > 6 && !memcmp(buf+2, "From ", 5))) {
476                 for(i=2; i < n; i++ )
477                     buf[i-2] = buf[i];
478                 n -= 2;
479                 buf[n] = 0; /* not really needed */
480                 state = state == fhdrCHECKDashEscaped3 ? fhdrTEXT :
481                         state == fhdrCHECKDashEscaped2 ?
482                                  fhdrREADClearsig : fhdrTESTSpaces;
483             }
484             else {
485                 log_error(_("invalid dash escaped line: "));
486                 print_string( stderr, buf, n, 0 );
487                 putc('\n', stderr);
488                 state = fhdrERROR;
489             }
490             break;
491
492           case fhdrCHECKClearsig:
493             /* check the clearsig line */
494             if( n > 15 && !memcmp(buf, "-----", 5 ) )
495                 state = fhdrENDClearsig;
496             else if( buf[0] == '-' && buf[1] == ' ' )
497                 state = fhdrCHECKDashEscaped;
498             else {
499                 state = fhdrTESTSpaces;
500             }
501             break;
502
503           case fhdrCHECKClearsig2:
504             /* check the clearsig line */
505             if( n > 15 && !memcmp(buf, "-----", 5 ) )
506                 state = fhdrENDClearsig;
507             else if( buf[0] == '-' && buf[1] == ' ' )
508                 state = fhdrCHECKDashEscaped2;
509             else {
510                 state = fhdrREADClearsig;
511             }
512             break;
513
514           case fhdrREADClearsigNext:
515             /* Read to the end of the line, do not care about checking
516              * for dashed escaped text of headers */
517             c = 0;
518             n = 0;
519             while( n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n' )
520                 buf[n++] = c;
521             buf[n] = 0;
522             if( c == -1 )
523                 state = fhdrEOF;
524             else if( c == '\n' )
525                 state = fhdrREADClearsig;
526             else
527                 state = fhdrTESTSpaces;
528             break;
529
530           case fhdrTESTSpaces: {
531             /* but must check whether the rest of the line
532              * only contains white spaces; this is problematic
533              * since we may have to restore the stuff.  simply
534              * counting spaces is not enough, because it may be a
535              * mix of different white space characters */
536             IOBUF b = iobuf_temp();
537             while( (c=iobuf_get2(a)) != -1 && c != '\n' ) {
538                 iobuf_put(b,c);
539                 if( c != ' ' && c != '\t' && c != '\r' )
540                     break;
541             }
542             if( c == '\n' ) {
543                 /* okay we can skip the rest of the line */
544                 iobuf_close(b);
545                 state = fhdrREADClearsig;
546             }
547             else {
548                 iobuf_unget_and_close_temp(a,b);
549                 state = fhdrREADClearsigNext;
550             }
551           } break;
552
553           case fhdrERRORShow:
554             log_error(_("invalid clear text header: "));
555             print_string( stderr, buf, n, 0 );
556             putc('\n', stderr);
557             state = fhdrERROR;
558             break;
559
560           default: BUG();
561         }
562         switch( state ) {
563           case fhdrINIT:
564           case fhdrINITCont:
565           case fhdrINITSkip:
566           case fhdrCHECKBegin:
567           case fhdrWAITHeader:
568           case fhdrWAITClearsig:
569           case fhdrSKIPHeader:
570           case fhdrEMPTYClearsig:
571           case fhdrCHECKClearsig:
572           case fhdrCHECKClearsig2:
573           case fhdrCHECKDashEscaped:
574           case fhdrCHECKDashEscaped2:
575           case fhdrCHECKDashEscaped3:
576           case fhdrTESTSpaces:
577           case fhdrERRORShow:
578             cont = 1;
579             break;
580           default: cont = 0;
581         }
582     } while( cont );
583
584     if( clearsig && state == fhdrTEXT )
585         state = fhdrCLEARSIG;
586
587     if( state == fhdrCLEARSIG || state == fhdrREADClearsig ) {
588         /* append CR,LF after removing trailing wspaces */
589         for(p=buf+n-1; n; n--, p-- ) {
590             assert( *p != '\n' );
591             if( *p != ' ' && *p != '\t' && *p != '\r' ) {
592                 p[1] = '\r';
593                 p[2] = '\n';
594                 n += 2;
595                 break;
596             }
597         }
598         if( !n ) {
599             buf[0] = '\r';
600             buf[1] = '\n';
601             n = 2;
602         }
603     }
604
605     *r_buflen = n;
606     *r_empty = empty;
607     return state;
608 }
609
610
611 /* figure out whether the data is armored or not */
612 static int
613 check_input( armor_filter_context_t *afx, IOBUF a )
614 {
615     int rc = 0;
616     size_t n;
617     fhdr_state_t state = afx->parse_state;
618     unsigned emplines;
619
620     if( state != fhdrENDClearsig )
621         state = fhdrHASArmor;
622
623     n = DIM(afx->helpbuf);
624     state = find_header( state, afx->helpbuf, &n, a,
625                                 afx->helplen, &emplines, &afx->hashes);
626     switch( state ) {
627       case fhdrNOArmor:
628         afx->inp_checked = 1;
629         afx->inp_bypass = 1;
630         afx->helplen = n;
631         break;
632
633       case fhdrERROR:
634         invalid_armor();
635         break;
636
637       case fhdrEOF:
638         rc = -1;
639         break;
640
641       case fhdrNullClearsig:
642       case fhdrCLEARSIG: /* start fake package mode (for clear signatures) */
643         afx->helplen = n;
644         afx->helpidx = 0;
645         afx->faked = 1;
646         break;
647
648       case fhdrTEXT:
649         afx->helplen = n;
650         afx->helpidx = 0;
651         afx->inp_checked = 1;
652         afx->crc = CRCINIT;
653         afx->idx = 0;
654         afx->radbuf[0] = 0;
655         break;
656
657       default: BUG();
658     }
659
660     afx->parse_state = state;
661     return rc;
662 }
663
664
665
666 /* fake a literal data packet and wait for an armor line */
667 static int
668 fake_packet( armor_filter_context_t *afx, IOBUF a,
669              size_t *retn, byte *buf, size_t size  )
670 {
671     int rc = 0;
672     size_t len = 0;
673     size_t n, nn;
674     fhdr_state_t state = afx->parse_state;
675     unsigned emplines = afx->empty;
676
677     len = 2;    /* reserve 2 bytes for the length header */
678     size -= 3;  /* and 1 for empline handling and 2 for the term header */
679     while( !rc && len < size ) {
680         if( emplines ) {
681             while( emplines && len < size ) {
682                 buf[len++] = '\r';
683                 buf[len++] = '\n';
684                 emplines--;
685             }
686             continue;
687         }
688         if( state == fhdrENDClearsigHelp ) {
689             state = fhdrENDClearsig;
690             afx->faked = 0;
691             rc = -1;
692             continue;
693         }
694         if( state != fhdrNullClearsig
695             && afx->helpidx < afx->helplen ) { /* flush the last buffer */
696             n = afx->helplen;
697             for(nn=afx->helpidx; len < size && nn < n ; nn++ )
698                 buf[len++] = afx->helpbuf[nn];
699             afx->helpidx = nn;
700             continue;
701         }
702         if( state == fhdrEOF ) {
703             rc = -1;
704             continue;
705         }
706         /* read a new one */
707         n = DIM(afx->helpbuf);
708         afx->helpidx = 0;
709         state = find_header( state, afx->helpbuf, &n, a,
710                               state == fhdrNullClearsig? afx->helplen:0,
711                                                 &emplines, &afx->hashes );
712         switch( state) {
713           case fhdrERROR:
714             invalid_armor();
715             break;
716
717           case fhdrEOF:
718             rc = -1;
719             break;
720
721           case fhdrCLEARSIG:
722             BUG();
723
724           case fhdrREADClearsig:
725           case fhdrREADClearsigNext:
726             afx->helplen = n;
727             break;
728
729           case fhdrENDClearsig:
730             state = fhdrENDClearsigHelp;
731             afx->helplen = n;
732             break;
733
734           default: BUG();
735         }
736     }
737     buf[0] = (len-2) >> 8;
738     buf[1] = (len-2);
739     if( state == fhdrENDClearsig ) { /* write last (ending) length header */
740         if( buf[0] || buf[1] ) { /* write only if length of text is > 0 */
741             buf[len++] = 0;
742             buf[len++] = 0;
743         }
744         rc = 0;
745     }
746
747     afx->parse_state = state;
748     afx->empty = emplines;
749     *retn = len;
750     return rc;
751 }
752
753
754
755 static int
756 radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
757               byte *buf, size_t size )
758 {
759     byte val;
760     int c, c2;
761     int checkcrc=0;
762     int rc = 0;
763     size_t n = 0;
764     int  idx, i;
765     u32 crc;
766
767     crc = afx->crc;
768     idx = afx->idx;
769     val = afx->radbuf[0];
770     for( n=0; n < size; ) {
771         if( afx->helpidx < afx->helplen )
772             c = afx->helpbuf[afx->helpidx++];
773         else if( (c=iobuf_get(a)) == -1 )
774             break;
775         if( c == '\n' || c == ' ' || c == '\r' || c == '\t' )
776             continue;
777         else if( c == '=' ) { /* pad character: stop */
778             if( idx == 1 )
779                 buf[n++] = val;
780             checkcrc++;
781             break;
782         }
783         else if( (c = asctobin[(c2=c)]) == 255 ) {
784             log_error(_("invalid radix64 character %02x skipped\n"), c2);
785             continue;
786         }
787         switch(idx) {
788           case 0: val =  c << 2; break;
789           case 1: val |= (c>>4)&3; buf[n++]=val;val=(c<<4)&0xf0;break;
790           case 2: val |= (c>>2)&15; buf[n++]=val;val=(c<<6)&0xc0;break;
791           case 3: val |= c&0x3f; buf[n++] = val; break;
792         }
793         idx = (idx+1) % 4;
794     }
795     for(i=0; i < n; i++ )
796         crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]];
797     crc &= 0x00ffffff;
798     afx->crc = crc;
799     afx->idx = idx;
800     afx->radbuf[0] = val;
801     if( checkcrc ) {
802         afx->any_data = 1;
803         afx->inp_checked=0;
804         afx->faked = 0;
805         afx->parse_state = 0;
806         for(;;) { /* skip lf and pad characters */
807             if( afx->helpidx < afx->helplen )
808                 c = afx->helpbuf[afx->helpidx++];
809             else if( (c=iobuf_get(a)) == -1 )
810                 break;
811             if( c == '\n' || c == ' ' || c == '\r'
812                 || c == '\t' || c == '=' )
813                 continue;
814             break;
815         }
816         if( c == -1 )
817             log_error(_("premature eof (no CRC)\n"));
818         else {
819             u32 mycrc = 0;
820             idx = 0;
821             do {
822                 if( (c = asctobin[c]) == 255 )
823                     break;
824                 switch(idx) {
825                   case 0: val =  c << 2; break;
826                   case 1: val |= (c>>4)&3; mycrc |= val << 16;val=(c<<4)&0xf0;break;
827                   case 2: val |= (c>>2)&15; mycrc |= val << 8;val=(c<<6)&0xc0;break;
828                   case 3: val |= c&0x3f; mycrc |= val; break;
829                 }
830                 if( afx->helpidx < afx->helplen )
831                     c = afx->helpbuf[afx->helpidx++];
832                 else if( (c=iobuf_get(a)) == -1 )
833                     break;
834             } while( ++idx < 4 );
835             if( c == -1 ) {
836                 log_error(_("premature eof (in CRC)\n"));
837                 rc = G10ERR_INVALID_ARMOR;
838             }
839             else if( idx != 4 ) {
840                 log_error(_("malformed CRC\n"));
841                 rc = G10ERR_INVALID_ARMOR;
842             }
843             else if( mycrc != afx->crc ) {
844                 log_error(_("CRC error; %06lx - %06lx\n"),
845                                     (ulong)afx->crc, (ulong)mycrc);
846                 rc = G10ERR_INVALID_ARMOR;
847             }
848             else {
849                 rc = 0;
850               #if 0
851                 for(rc=0;!rc;) {
852                     rc = 0 /*check_trailer( &fhdr, c )*/;
853                     if( !rc ) {
854                         if( afx->helpidx < afx->helplen )
855                             c = afx->helpbuf[afx->helpidx++];
856                         else if( (c=iobuf_get(a)) == -1 )
857                             rc = 2;
858                     }
859                 }
860                 if( rc == -1 )
861                     rc = 0;
862                 else if( rc == 2 ) {
863                     log_error(_("premature eof (in Trailer)\n"));
864                     rc = G10ERR_INVALID_ARMOR;
865                 }
866                 else {
867                     log_error(_("error in trailer line\n"));
868                     rc = G10ERR_INVALID_ARMOR;
869                 }
870               #endif
871             }
872         }
873     }
874
875     if( !n )
876         rc = -1;
877
878     *retn = n;
879     return rc;
880 }
881
882 /****************
883  * This filter is used to handle the armor stuff
884  */
885 int
886 armor_filter( void *opaque, int control,
887              IOBUF a, byte *buf, size_t *ret_len)
888 {
889     size_t size = *ret_len;
890     armor_filter_context_t *afx = opaque;
891     int rc=0, i, c;
892     byte radbuf[3];
893     int  idx, idx2;
894     size_t n=0;
895     u32 crc;
896   #if 0
897     static FILE *fp ;
898
899     if( !fp ) {
900         fp = fopen("armor.out", "w");
901         assert(fp);
902     }
903   #endif
904
905     if( DBG_FILTER )
906         log_debug("armor-filter: control: %d\n", control );
907     if( control == IOBUFCTRL_UNDERFLOW && afx->inp_bypass ) {
908         for( n=0; n < size; n++ ) {
909             if( (c=iobuf_get(a)) == -1 )
910                 break;
911             buf[n] = c & 0xff;
912         }
913         if( !n )
914             rc = -1;
915         *ret_len = n;
916     }
917     else if( control == IOBUFCTRL_UNDERFLOW ) {
918         if( size < 15+(4*15) )  /* need space for up to 4 onepass_sigs */
919             BUG(); /* supplied buffer too short */
920
921         if( afx->faked )
922             rc = fake_packet( afx, a, &n, buf, size );
923         else if( !afx->inp_checked ) {
924             rc = check_input( afx, a );
925             if( afx->inp_bypass ) {
926                 for( n=0; n < size && n < afx->helplen; n++ )
927                     buf[n] = afx->helpbuf[n];
928                 if( !n )
929                     rc = -1;
930                 assert( n == afx->helplen );
931                 afx->helplen = 0;
932             }
933             else if( afx->faked ) {
934                 unsigned hashes = afx->hashes;
935                 /* the buffer is at least 15+n*15 bytes long, so it
936                  * is easy to construct the packets */
937
938                 hashes &= 1|2|4|8;
939                 if( !hashes )
940                     hashes |= 4;  /* default to MD 5 */
941                 n=0;
942                 do {
943                     /* first some onepass signature packets */
944                     buf[n++] = 0x90; /* old format, type 4, 1 length byte */
945                     buf[n++] = 13;   /* length */
946                     buf[n++] = 3;    /* version */
947                     buf[n++] = 0x01; /* sigclass 0x01 (canonical text mode)*/
948                     if( hashes & 1 ) {
949                         hashes &= ~1;
950                         buf[n++] = DIGEST_ALGO_RMD160;
951                     }
952                     else if( hashes & 2 ) {
953                         hashes &= ~2;
954                         buf[n++] = DIGEST_ALGO_SHA1;
955                     }
956                     else if( hashes & 4 ) {
957                         hashes &= ~4;
958                         buf[n++] = DIGEST_ALGO_MD5;
959                     }
960                     else if( hashes & 8 ) {
961                         hashes &= ~8;
962                         buf[n++] = DIGEST_ALGO_TIGER;
963                     }
964                     else
965                         buf[n++] = 0;    /* (don't know) */
966
967                     buf[n++] = 0;    /* public key algo (don't know) */
968                     memset(buf+n, 0, 8); /* don't know the keyid */
969                     n += 8;
970                     buf[n++] = !hashes;   /* last one */
971                 } while( hashes );
972
973                 /* followed by a plaintext packet */
974                 buf[n++] = 0xaf; /* old packet format, type 11, var length */
975                 buf[n++] = 0;    /* set the length header */
976                 buf[n++] = 6;
977                 buf[n++] = 't';  /* canonical text mode */
978                 buf[n++] = 0;    /* namelength */
979                 memset(buf+n, 0, 4); /* timestamp */
980                 n += 4;
981             }
982             else if( !rc )
983                 rc = radix64_read( afx, a, &n, buf, size );
984         }
985         else
986             rc = radix64_read( afx, a, &n, buf, size );
987       #if 0
988         if( n )
989             if( fwrite(buf, n, 1, fp ) != 1 )
990                 BUG();
991       #endif
992         *ret_len = n;
993     }
994     else if( control == IOBUFCTRL_FLUSH ) {
995         if( !afx->status ) { /* write the header line */
996             if( afx->what >= DIM(head_strings) )
997                 log_bug("afx->what=%d", afx->what);
998             iobuf_writestr(a, "-----");
999             iobuf_writestr(a, head_strings[afx->what] );
1000             iobuf_writestr(a, "-----\n");
1001             iobuf_writestr(a, "Version: GNUPG v"  VERSION " ("
1002                                             PRINTABLE_OS_NAME ")\n");
1003
1004             if( opt.comment_string ) {
1005                 const char *s = opt.comment_string;
1006                 iobuf_writestr(a, "Comment: " );
1007                 for( ; *s; s++ ) {
1008                     if( *s == '\n' )
1009                         iobuf_writestr(a, "\\n" );
1010                     else if( *s == '\r' )
1011                         iobuf_writestr(a, "\\r" );
1012                     else if( *s == '\v' )
1013                         iobuf_writestr(a, "\\v" );
1014                     else
1015                         iobuf_put(a, *s );
1016                 }
1017                 iobuf_put(a, '\n' );
1018             }
1019             else
1020                 iobuf_writestr(a,
1021                     "Comment: For info finger gcrypt@ftp.guug.de\n");
1022             if( afx->hdrlines )
1023                 iobuf_writestr(a, afx->hdrlines);
1024             iobuf_put(a, '\n');
1025             afx->status++;
1026             afx->idx = 0;
1027             afx->idx2 = 0;
1028             afx->crc = CRCINIT;
1029         }
1030         crc = afx->crc;
1031         idx = afx->idx;
1032         idx2 = afx->idx2;
1033         for(i=0; i < idx; i++ )
1034             radbuf[i] = afx->radbuf[i];
1035
1036         for(i=0; i < size; i++ )
1037             crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]];
1038         crc &= 0x00ffffff;
1039
1040         for( ; size; buf++, size-- ) {
1041             radbuf[idx++] = *buf;
1042             if( idx > 2 ) {
1043                 idx = 0;
1044                 c = bintoasc[(*radbuf >> 2) & 077];
1045                 iobuf_put(a, c);
1046                 c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
1047                 iobuf_put(a, c);
1048                 c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
1049                 iobuf_put(a, c);
1050                 c = bintoasc[radbuf[2]&077];
1051                 iobuf_put(a, c);
1052                 if( ++idx2 >= (72/4) ) {
1053                     iobuf_put(a, '\n');
1054                     idx2=0;
1055                 }
1056             }
1057         }
1058         for(i=0; i < idx; i++ )
1059             afx->radbuf[i] = radbuf[i];
1060         afx->idx = idx;
1061         afx->idx2 = idx2;
1062         afx->crc  = crc;
1063     }
1064     else if( control == IOBUFCTRL_INIT ) {
1065         if( !is_initialized )
1066             initialize();
1067     }
1068     else if( control == IOBUFCTRL_FREE ) {
1069         if( afx->status ) { /* pad, write cecksum, and bottom line */
1070             crc = afx->crc;
1071             idx = afx->idx;
1072             idx2 = afx->idx2;
1073             for(i=0; i < idx; i++ )
1074                 radbuf[i] = afx->radbuf[i];
1075             if( idx ) {
1076                 c = bintoasc[(*radbuf>>2)&077];
1077                 iobuf_put(a, c);
1078                 if( idx == 1 ) {
1079                     c = bintoasc[((*radbuf << 4) & 060) & 077];
1080                     iobuf_put(a, c);
1081                     iobuf_put(a, '=');
1082                     iobuf_put(a, '=');
1083                 }
1084                 else { /* 2 */
1085                     c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
1086                     iobuf_put(a, c);
1087                     c = bintoasc[((radbuf[1] << 2) & 074) & 077];
1088                     iobuf_put(a, c);
1089                     iobuf_put(a, '=');
1090                 }
1091                 if( ++idx2 >= (72/4) ) {
1092                     iobuf_put(a, '\n');
1093                     idx2=0;
1094                 }
1095             }
1096             /* may need a linefeed */
1097             if( idx2 )
1098                 iobuf_put(a, '\n');
1099             /* write the CRC */
1100             iobuf_put(a, '=');
1101             radbuf[0] = crc >>16;
1102             radbuf[1] = crc >> 8;
1103             radbuf[2] = crc;
1104             c = bintoasc[(*radbuf >> 2) & 077];
1105             iobuf_put(a, c);
1106             c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
1107             iobuf_put(a, c);
1108             c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
1109             iobuf_put(a, c);
1110             c = bintoasc[radbuf[2]&077];
1111             iobuf_put(a, c);
1112             iobuf_put(a, '\n');
1113             /* and the the trailer */
1114             if( afx->what >= DIM(tail_strings) )
1115                 log_bug("afx->what=%d", afx->what);
1116             iobuf_writestr(a, "-----");
1117             iobuf_writestr(a, tail_strings[afx->what] );
1118             iobuf_writestr(a, "-----\n");
1119         }
1120         else if( !afx->any_data && !afx->inp_bypass )
1121             log_error(_("no valid RFC1991 or OpenPGP data found.\n"));
1122     }
1123     else if( control == IOBUFCTRL_DESC )
1124         *(char**)buf = "armor_filter";
1125     return rc;
1126 }
1127
1128
1129