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