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