7fe2f81725d6a6623066b5b6568d672571122b19
[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;
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 all empty lines (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                 if( !n || (buf[0]=='\r' && !buf[1]) ) /* empty line */
390                     ;
391                 else
392                     state = fhdrCHECKDashEscaped3;
393             }
394             else {
395                 /* fixme: we should check whether this line continues
396                  *   it is possible that we have only read ws until here
397                  *   and more stuff is to come */
398                 state = fhdrEOF;
399             }
400             break;
401
402           case fhdrENDClearsig:
403           case fhdrCHECKBegin:
404             state = state == fhdrCHECKBegin ? fhdrINITSkip : fhdrERRORShow;
405             if( n < 15 )
406                 break;  /* too short */
407             if( memcmp( buf, "-----", 5 ) )
408                 break;
409             buf[n] = 0;
410             p = strstr(buf+5, "-----");
411             if( !p )
412                 break;
413             *p = 0;
414             p += 5;
415             if( *p == '\r' )
416                 p++;
417             if( *p )
418                 break; /* garbage after dashes */
419             p = buf+5;
420             for(i=0; (s=head_strings[i]); i++ )
421                 if( !strcmp(s, p) )
422                     break;
423             if( !s )
424                 break; /* unknown begin line */
425             /* found the begin line */
426             hdr_line = i;
427             state = fhdrWAITHeader;
428             if( hdr_line == BEGIN_SIGNED_MSG_IDX )
429                 clearsig = 1;
430             if( opt.verbose > 1 )
431                 log_info("armor: %s\n", head_strings[hdr_line]);
432             break;
433
434           case fhdrCLEARSIG:
435           case fhdrEMPTYClearsig:
436           case fhdrREADClearsig:
437             /* we are at the start of a line: read a clearsig into the buffer
438              * we have to look for a header line or dashed escaped text*/
439             n = 0;
440             c = 0;
441             while( n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n' )
442                 buf[n++] = c;
443             buf[n] = 0;
444             if( c == -1 )
445                 state = fhdrEOF;
446             else if( !n || ( buf[0]=='\r' && !buf[1] ) ) {
447                 state = fhdrEMPTYClearsig;
448                 empty++;
449             }
450             else if( c == '\n' )
451                 state = fhdrCHECKClearsig2;
452             else
453                 state = fhdrCHECKClearsig;
454             break;
455
456           case fhdrCHECKDashEscaped3:
457             if( !(n > 1 && buf[0] == '-' && buf[1] == ' ' ) ) {
458                 state = fhdrTEXT;
459                 break;
460             }
461             /* fall through */
462           case fhdrCHECKDashEscaped2:
463           case fhdrCHECKDashEscaped:
464             /* check dash escaped line */
465             if( buf[2] == '-' || ( n > 6 && !memcmp(buf+2, "From ", 5))) {
466                 for(i=2; i < n; i++ )
467                     buf[i-2] = buf[i];
468                 n -= 2;
469                 buf[n] = 0; /* not really needed */
470                 state = state == fhdrCHECKDashEscaped3 ? fhdrTEXT :
471                         state == fhdrCHECKDashEscaped2 ?
472                                  fhdrREADClearsig : fhdrTESTSpaces;
473             }
474             else {
475                 log_error("invalid dash escaped line: ");
476                 print_string( stderr, buf, n, 0 );
477                 putc('\n', stderr);
478                 state = fhdrERROR;
479             }
480             break;
481
482           case fhdrCHECKClearsig:
483             /* check the clearsig line */
484             if( n > 15 && !memcmp(buf, "-----", 5 ) )
485                 state = fhdrENDClearsig;
486             else if( buf[0] == '-' && buf[1] == ' ' )
487                 state = fhdrCHECKDashEscaped;
488             else {
489                 state = fhdrTESTSpaces;
490             }
491             break;
492
493           case fhdrCHECKClearsig2:
494             /* check the clearsig line */
495             if( n > 15 && !memcmp(buf, "-----", 5 ) )
496                 state = fhdrENDClearsig;
497             else if( buf[0] == '-' && buf[1] == ' ' )
498                 state = fhdrCHECKDashEscaped2;
499             else {
500                 state = fhdrREADClearsig;
501             }
502             break;
503
504           case fhdrREADClearsigNext:
505             /* Read to the end of the line, do not care about checking
506              * for dashed escaped text of headers */
507             c = 0;
508             n = 0;
509             while( n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n' )
510                 buf[n++] = c;
511             buf[n] = 0;
512             if( c == -1 )
513                 state = fhdrEOF;
514             else if( c == '\n' )
515                 state = fhdrREADClearsig;
516             else
517                 state = fhdrTESTSpaces;
518             break;
519
520           case fhdrTESTSpaces: {
521             /* but must check whether the rest of the line
522              * only contains white spaces; this is problematic
523              * since we may have to restore the stuff.  simply
524              * counting spaces is not enough, because it may be a
525              * mix of different white space characters */
526             IOBUF b = iobuf_temp();
527             while( (c=iobuf_get2(a)) != -1 && c != '\n' ) {
528                 iobuf_put(b,c);
529                 if( c != ' ' && c != '\t' && c != '\r' )
530                     break;
531             }
532             if( c == '\n' ) {
533                 /* okay we can skip the rest of the line */
534                 iobuf_close(b);
535                 state = fhdrREADClearsig;
536             }
537             else {
538                 iobuf_unget_and_close_temp(a,b);
539                 state = fhdrREADClearsigNext;
540             }
541           } break;
542
543           case fhdrERRORShow:
544             log_error("invalid clear text header: ");
545             print_string( stderr, buf, n, 0 );
546             putc('\n', stderr);
547             state = fhdrERROR;
548             break;
549
550           default: BUG();
551         }
552         switch( state ) {
553           case fhdrINIT:
554           case fhdrINITCont:
555           case fhdrINITSkip:
556           case fhdrCHECKBegin:
557           case fhdrWAITHeader:
558           case fhdrWAITClearsig:
559           case fhdrSKIPHeader:
560           case fhdrEMPTYClearsig:
561           case fhdrCHECKClearsig:
562           case fhdrCHECKClearsig2:
563           case fhdrCHECKDashEscaped:
564           case fhdrCHECKDashEscaped2:
565           case fhdrCHECKDashEscaped3:
566           case fhdrTESTSpaces:
567           case fhdrERRORShow:
568             cont = 1;
569             break;
570           default: cont = 0;
571         }
572     } while( cont );
573
574     if( clearsig && state == fhdrTEXT )
575         state = fhdrCLEARSIG;
576
577     if( state == fhdrCLEARSIG || state == fhdrREADClearsig ) {
578         /* append CR,LF after removing trailing wspaces */
579         for(p=buf+n-1; n; n--, p-- ) {
580             assert( *p != '\n' );
581             if( *p != ' ' && *p != '\t' && *p != '\r' ) {
582                 p[1] = '\r';
583                 p[2] = '\n';
584                 n += 2;
585                 break;
586             }
587         }
588         if( !n ) {
589             buf[0] = '\r';
590             buf[1] = '\n';
591             n = 2;
592         }
593     }
594
595
596     *r_buflen = n;
597     *r_empty = empty;
598     return state;
599 }
600
601
602 /* figure out whether the data is armored or not */
603 static int
604 check_input( armor_filter_context_t *afx, IOBUF a )
605 {
606     int rc = 0;
607     size_t n;
608     fhdr_state_t state = afx->parse_state;
609     unsigned emplines;
610
611     if( state != fhdrENDClearsig )
612         state = fhdrHASArmor;
613
614     n = DIM(afx->helpbuf);
615     state = find_header( state, afx->helpbuf, &n, a,
616                                 afx->helplen, &emplines, &afx->hashes);
617     switch( state ) {
618       case fhdrNOArmor:
619         afx->inp_checked = 1;
620         afx->inp_bypass = 1;
621         afx->helplen = n;
622         break;
623
624       case fhdrERROR:
625         invalid_armor();
626         break;
627
628       case fhdrEOF:
629         rc = -1;
630         break;
631
632       case fhdrCLEARSIG: /* start fake package mode (for clear signatures) */
633         afx->helplen = n;
634         afx->helpidx = 0;
635         afx->faked = 1;
636         break;
637
638       case fhdrTEXT:
639         afx->helplen = n;
640         afx->helpidx = 0;
641         afx->inp_checked = 1;
642         afx->crc = CRCINIT;
643         afx->idx = 0;
644         afx->radbuf[0] = 0;
645         break;
646
647       default: BUG();
648     }
649
650     afx->parse_state = state;
651     return rc;
652 }
653
654
655
656 /* fake a literal data packet and wait for an armor line */
657 static int
658 fake_packet( armor_filter_context_t *afx, IOBUF a,
659              size_t *retn, byte *buf, size_t size  )
660 {
661     int rc = 0;
662     size_t len = 0;
663     size_t n, nn;
664     fhdr_state_t state = afx->parse_state;
665     unsigned emplines = afx->empty;
666
667     len = 2;    /* reserve 2 bytes for the length header */
668     size -= 3;  /* and 1 for empline handling and 2 for the term header */
669     while( !rc && len < size ) {
670         if( emplines ) {
671             while( emplines && len < size ) {
672                 buf[len++] = '\r';
673                 buf[len++] = '\n';
674                 emplines--;
675             }
676             continue;
677         }
678         if( state == fhdrENDClearsigHelp ) {
679             state = fhdrENDClearsig;
680             afx->faked = 0;
681             rc = -1;
682             continue;
683         }
684         if( afx->helpidx < afx->helplen ) { /* flush the last buffer */
685             n = afx->helplen;
686             for(nn=afx->helpidx; len < size && nn < n ; nn++ )
687                 buf[len++] = afx->helpbuf[nn];
688             afx->helpidx = nn;
689             continue;
690         }
691         if( state == fhdrEOF ) {
692             rc = -1;
693             continue;
694         }
695         /* read a new one */
696         n = DIM(afx->helpbuf);
697         afx->helpidx = 0;
698         state = find_header( state, afx->helpbuf, &n, a, 0,
699                                                 &emplines, &afx->hashes );
700         switch( state) {
701           case fhdrERROR:
702             invalid_armor();
703             break;
704
705           case fhdrEOF:
706             rc = -1;
707             break;
708
709           case fhdrCLEARSIG:
710             BUG();
711
712           case fhdrREADClearsig:
713           case fhdrREADClearsigNext:
714             afx->helplen = n;
715             break;
716
717           case fhdrENDClearsig:
718             /* FIXME: this is wrong: Only the last CRLF should
719              * not be included in the hash, muts rewrite the FSM again
720              * This proble does only occur if the last line does not end
721              * in with a LF?
722              */
723             if( emplines )
724                 emplines--; /* don't count the last one */
725             state = fhdrENDClearsigHelp;
726             afx->helplen = n;
727             break;
728
729           default: BUG();
730         }
731     }
732     buf[0] = (len-2) >> 8;
733     buf[1] = (len-2);
734     if( state == fhdrENDClearsig ) { /* write last (ending) length header */
735         buf[len++] = 0;
736         buf[len++] = 0;
737         rc = 0;
738     }
739
740     afx->parse_state = state;
741     afx->empty = emplines;
742     *retn = len;
743     return rc;
744 }
745
746
747
748 static int
749 radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
750               byte *buf, size_t size )
751 {
752     byte val;
753     int c, c2;
754     int checkcrc=0;
755     int rc = 0;
756     size_t n = 0;
757     int  idx, i;
758     u32 crc;
759
760     crc = afx->crc;
761     idx = afx->idx;
762     val = afx->radbuf[0];
763     for( n=0; n < size; ) {
764         if( afx->helpidx < afx->helplen )
765             c = afx->helpbuf[afx->helpidx++];
766         else if( (c=iobuf_get(a)) == -1 )
767             break;
768         if( c == '\n' || c == ' ' || c == '\r' || c == '\t' )
769             continue;
770         else if( c == '=' ) { /* pad character: stop */
771             if( idx == 1 )
772                 buf[n++] = val;
773             checkcrc++;
774             break;
775         }
776         else if( (c = asctobin[(c2=c)]) == 255 ) {
777             log_error("invalid radix64 character %02x skipped\n", c2);
778             continue;
779         }
780         switch(idx) {
781           case 0: val =  c << 2; break;
782           case 1: val |= (c>>4)&3; buf[n++]=val;val=(c<<4)&0xf0;break;
783           case 2: val |= (c>>2)&15; buf[n++]=val;val=(c<<6)&0xc0;break;
784           case 3: val |= c&0x3f; buf[n++] = val; break;
785         }
786         idx = (idx+1) % 4;
787     }
788     for(i=0; i < n; i++ )
789         crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]];
790     crc &= 0x00ffffff;
791     afx->crc = crc;
792     afx->idx = idx;
793     afx->radbuf[0] = val;
794     if( checkcrc ) {
795         afx->inp_eof = 1; /*assume eof */
796         for(;;) { /* skip lf and pad characters */
797             if( afx->helpidx < afx->helplen )
798                 c = afx->helpbuf[afx->helpidx++];
799             else if( (c=iobuf_get(a)) == -1 )
800                 break;
801             if( c == '\n' || c == ' ' || c == '\r'
802                 || c == '\t' || c == '=' )
803                 continue;
804             break;
805         }
806         if( c == -1 )
807             log_error("premature eof (no CRC)\n");
808         else {
809             u32 mycrc = 0;
810             idx = 0;
811             do {
812                 if( (c = asctobin[c]) == 255 )
813                     break;
814                 switch(idx) {
815                   case 0: val =  c << 2; break;
816                   case 1: val |= (c>>4)&3; mycrc |= val << 16;val=(c<<4)&0xf0;break;
817                   case 2: val |= (c>>2)&15; mycrc |= val << 8;val=(c<<6)&0xc0;break;
818                   case 3: val |= c&0x3f; mycrc |= val; break;
819                 }
820                 if( afx->helpidx < afx->helplen )
821                     c = afx->helpbuf[afx->helpidx++];
822                 else if( (c=iobuf_get(a)) == -1 )
823                     break;
824             } while( ++idx < 4 );
825             if( c == -1 )
826                 log_error("premature eof (in CRC)\n");
827             else if( idx != 4 )
828                 log_error("malformed CRC\n");
829             else if( mycrc != afx->crc )
830                 log_error("CRC error; %06lx - %06lx\n",
831                                     (ulong)afx->crc, (ulong)mycrc);
832             else {
833                 rc = 0;
834               #if 0
835                 for(rc=0;!rc;) {
836                     rc = 0 /*check_trailer( &fhdr, c )*/;
837                     if( !rc ) {
838                         if( afx->helpidx < afx->helplen )
839                             c = afx->helpbuf[afx->helpidx++];
840                         else if( (c=iobuf_get(a)) == -1 )
841                             rc = 2;
842                     }
843                 }
844                 if( rc == -1 )
845                     rc = 0;
846                 else if( rc == 2 )
847                     log_error("premature eof (in Trailer)\n");
848                 else
849                     log_error("error in trailer line\n");
850               #endif
851             }
852         }
853     }
854
855     if( !n )
856         rc = -1;
857
858     *retn = n;
859     return rc;
860 }
861
862
863 /****************
864  * This filter is used to handle the armor stuff
865  */
866 int
867 armor_filter( void *opaque, int control,
868              IOBUF a, byte *buf, size_t *ret_len)
869 {
870     size_t size = *ret_len;
871     armor_filter_context_t *afx = opaque;
872     int rc=0, i, c;
873     byte radbuf[3];
874     int  idx, idx2;
875     size_t n=0;
876     u32 crc;
877   #if 0
878     static FILE *fp ;
879
880     if( !fp ) {
881         fp = fopen("armor.out", "w");
882         assert(fp);
883     }
884   #endif
885
886     if( DBG_FILTER )
887         log_debug("armor-filter: control: %d\n", control );
888     if( control == IOBUFCTRL_UNDERFLOW && afx->inp_bypass ) {
889         for( n=0; n < size; n++ ) {
890             if( (c=iobuf_get(a)) == -1 )
891                 break;
892             buf[n] = c & 0xff;
893         }
894         if( !n )
895             rc = -1;
896         *ret_len = n;
897     }
898     else if( control == IOBUFCTRL_UNDERFLOW ) {
899         if( size < 15+(4*15) )  /* need space for up to 4 onepass_sigs */
900             BUG(); /* supplied buffer too short */
901
902         if( afx->inp_eof ) {
903             *ret_len = 0;
904             if( DBG_FILTER )
905                 log_debug("armor-filter: eof due to inp_eof flag\n" );
906             return -1;
907         }
908
909         if( afx->faked )
910             rc = fake_packet( afx, a, &n, buf, size );
911         else if( !afx->inp_checked ) {
912             rc = check_input( afx, a );
913             if( afx->inp_bypass ) {
914                 for( n=0; n < size && n < afx->helplen; n++ )
915                     buf[n] = afx->helpbuf[n];
916                 if( !n )
917                     rc = -1;
918                 assert( n == afx->helplen );
919                 afx->helplen = 0;
920             }
921             else if( afx->faked ) {
922                 unsigned hashes = afx->hashes;
923                 /* the buffer is at least 15+n*15 bytes long, so it
924                  * is easy to construct the packets */
925
926                 hashes &= 1|2|4|8;
927                 if( !hashes )
928                     hashes |= 4;  /* default to MD 5 */
929                 n=0;
930                 do {
931                     /* first some onepass signature packets */
932                     buf[n++] = 0x90; /* old format, type 4, 1 length byte */
933                     buf[n++] = 13;   /* length */
934                     buf[n++] = 3;    /* version */
935                     buf[n++] = 0x01; /* sigclass 0x01 (canonical text mode)*/
936                     if( hashes & 1 ) {
937                         hashes &= ~1;
938                         buf[n++] = DIGEST_ALGO_RMD160;
939                     }
940                     else if( hashes & 2 ) {
941                         hashes &= ~2;
942                         buf[n++] = DIGEST_ALGO_SHA1;
943                     }
944                     else if( hashes & 4 ) {
945                         hashes &= ~4;
946                         buf[n++] = DIGEST_ALGO_MD5;
947                     }
948                     else if( hashes & 8 ) {
949                         hashes &= ~8;
950                         buf[n++] = DIGEST_ALGO_TIGER;
951                     }
952                     else
953                         buf[n++] = 0;    /* (don't know) */
954
955                     buf[n++] = 0;    /* public key algo (don't know) */
956                     memset(buf+n, 0, 8); /* don't know the keyid */
957                     n += 8;
958                     buf[n++] = !hashes;   /* last one */
959                 } while( hashes );
960
961                 /* followed by a plaintext packet */
962                 buf[n++] = 0xaf; /* old packet format, type 11, var length */
963                 buf[n++] = 0;    /* set the length header */
964                 buf[n++] = 6;
965                 buf[n++] = 't';  /* canonical text mode */
966                 buf[n++] = 0;    /* namelength */
967                 memset(buf+n, 0, 4); /* timestamp */
968                 n += 4;
969             }
970             else if( !rc )
971                 rc = radix64_read( afx, a, &n, buf, size );
972         }
973         else
974             rc = radix64_read( afx, a, &n, buf, size );
975       #if 0
976         if( n )
977             if( fwrite(buf, n, 1, fp ) != 1 )
978                 BUG();
979       #endif
980         *ret_len = n;
981     }
982     else if( control == IOBUFCTRL_FLUSH ) {
983         if( !afx->status ) { /* write the header line */
984             if( afx->what >= DIM(head_strings) )
985                 log_bug("afx->what=%d", afx->what);
986             iobuf_writestr(a, "-----");
987             iobuf_writestr(a, head_strings[afx->what] );
988             iobuf_writestr(a, "-----\n");
989             iobuf_writestr(a, "Version: GNUPG v"  VERSION " ("
990                                             PRINTABLE_OS_NAME ")\n");
991             iobuf_writestr(a, "Comment: This is an alpha version!\n");
992             if( afx->hdrlines )
993                 iobuf_writestr(a, afx->hdrlines);
994             iobuf_put(a, '\n');
995             afx->status++;
996             afx->idx = 0;
997             afx->idx2 = 0;
998             afx->crc = CRCINIT;
999         }
1000         crc = afx->crc;
1001         idx = afx->idx;
1002         idx2 = afx->idx2;
1003         for(i=0; i < idx; i++ )
1004             radbuf[i] = afx->radbuf[i];
1005
1006         for(i=0; i < size; i++ )
1007             crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]];
1008         crc &= 0x00ffffff;
1009
1010         for( ; size; buf++, size-- ) {
1011             radbuf[idx++] = *buf;
1012             if( idx > 2 ) {
1013                 idx = 0;
1014                 c = bintoasc[(*radbuf >> 2) & 077];
1015                 iobuf_put(a, c);
1016                 c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
1017                 iobuf_put(a, c);
1018                 c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
1019                 iobuf_put(a, c);
1020                 c = bintoasc[radbuf[2]&077];
1021                 iobuf_put(a, c);
1022                 if( ++idx2 >= (72/4) ) {
1023                     iobuf_put(a, '\n');
1024                     idx2=0;
1025                 }
1026             }
1027         }
1028         for(i=0; i < idx; i++ )
1029             afx->radbuf[i] = radbuf[i];
1030         afx->idx = idx;
1031         afx->idx2 = idx2;
1032         afx->crc  = crc;
1033     }
1034     else if( control == IOBUFCTRL_INIT ) {
1035         if( !is_initialized )
1036             initialize();
1037     }
1038     else if( control == IOBUFCTRL_FREE ) {
1039         if( afx->status ) { /* pad, write cecksum, and bottom line */
1040             crc = afx->crc;
1041             idx = afx->idx;
1042             idx2 = afx->idx2;
1043             for(i=0; i < idx; i++ )
1044                 radbuf[i] = afx->radbuf[i];
1045             if( idx ) {
1046                 c = bintoasc[(*radbuf>>2)&077];
1047                 iobuf_put(a, c);
1048                 if( idx == 1 ) {
1049                     c = bintoasc[((*radbuf << 4) & 060) & 077];
1050                     iobuf_put(a, c);
1051                     iobuf_put(a, '=');
1052                     iobuf_put(a, '=');
1053                 }
1054                 else { /* 2 */
1055                     c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
1056                     iobuf_put(a, c);
1057                     c = bintoasc[((radbuf[1] << 2) & 074) & 077];
1058                     iobuf_put(a, c);
1059                     iobuf_put(a, '=');
1060                 }
1061                 if( ++idx2 >= (72/4) ) {
1062                     iobuf_put(a, '\n');
1063                     idx2=0;
1064                 }
1065             }
1066             /* may need a linefeed */
1067             if( idx2 )
1068                 iobuf_put(a, '\n');
1069             /* write the CRC */
1070             iobuf_put(a, '=');
1071             radbuf[0] = crc >>16;
1072             radbuf[1] = crc >> 8;
1073             radbuf[2] = crc;
1074             c = bintoasc[(*radbuf >> 2) & 077];
1075             iobuf_put(a, c);
1076             c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
1077             iobuf_put(a, c);
1078             c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
1079             iobuf_put(a, c);
1080             c = bintoasc[radbuf[2]&077];
1081             iobuf_put(a, c);
1082             iobuf_put(a, '\n');
1083             /* and the the trailer */
1084             if( afx->what >= DIM(tail_strings) )
1085                 log_bug("afx->what=%d", afx->what);
1086             iobuf_writestr(a, "-----");
1087             iobuf_writestr(a, tail_strings[afx->what] );
1088             iobuf_writestr(a, "-----\n");
1089         }
1090     }
1091     else if( control == IOBUFCTRL_DESC )
1092         *(char**)buf = "armor_filter";
1093     return rc;
1094 }
1095
1096
1097