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