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