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