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