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