intermediate release
[gnupg.git] / g10 / armor.c
1 /* armor.c - Armor filter
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GNUPG.
5  *
6  * GNUPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GNUPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27
28 #include "errors.h"
29 #include "iobuf.h"
30 #include "memory.h"
31 #include "util.h"
32 #include "filter.h"
33 #include "packet.h"
34 #include "options.h"
35 #include "main.h"
36 #include "status.h"
37
38
39 #define CRCINIT 0xB704CE
40 #define CRCPOLY 0X864CFB
41 #define CRCUPDATE(a,c) do {                                                 \
42                         a = ((a) << 8) ^ crc_table[((a)&0xff >> 16) ^ (c)]; \
43                         a &= 0x00ffffff;                                    \
44                     } while(0)
45 static u32 crc_table[256];
46 static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
47                          "abcdefghijklmnopqrstuvwxyz"
48                          "0123456789+/";
49 static byte asctobin[256]; /* runtime initialized */
50 static int is_initialized;
51
52
53 typedef enum {
54     fhdrHASArmor,
55     fhdrNOArmor,
56     fhdrINIT,
57     fhdrINITCont,
58     fhdrINITSkip,
59     fhdrCHECKBegin,
60     fhdrWAITHeader,
61     fhdrWAITClearsig,
62     fhdrSKIPHeader,
63     fhdrCLEARSIG,
64     fhdrREADClearsig,
65     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 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                 rc = G10ERR_INVALID_ARMOR;
828             }
829             else if( idx != 4 ) {
830                 log_error("malformed CRC\n");
831                 rc = G10ERR_INVALID_ARMOR;
832             }
833             else if( mycrc != afx->crc ) {
834                 log_error("CRC error; %06lx - %06lx\n",
835                                     (ulong)afx->crc, (ulong)mycrc);
836                 rc = G10ERR_INVALID_ARMOR;
837             }
838             else {
839                 rc = 0;
840               #if 0
841                 for(rc=0;!rc;) {
842                     rc = 0 /*check_trailer( &fhdr, c )*/;
843                     if( !rc ) {
844                         if( afx->helpidx < afx->helplen )
845                             c = afx->helpbuf[afx->helpidx++];
846                         else if( (c=iobuf_get(a)) == -1 )
847                             rc = 2;
848                     }
849                 }
850                 if( rc == -1 )
851                     rc = 0;
852                 else if( rc == 2 ) {
853                     log_error("premature eof (in Trailer)\n");
854                     rc = G10ERR_INVALID_ARMOR;
855                 }
856                 else {
857                     log_error("error in trailer line\n");
858                     rc = G10ERR_INVALID_ARMOR;
859                 }
860               #endif
861             }
862         }
863     }
864
865     if( !n )
866         rc = -1;
867
868     *retn = n;
869     return rc;
870 }
871
872
873 /****************
874  * This filter is used to handle the armor stuff
875  */
876 int
877 armor_filter( void *opaque, int control,
878              IOBUF a, byte *buf, size_t *ret_len)
879 {
880     size_t size = *ret_len;
881     armor_filter_context_t *afx = opaque;
882     int rc=0, i, c;
883     byte radbuf[3];
884     int  idx, idx2;
885     size_t n=0;
886     u32 crc;
887   #if 0
888     static FILE *fp ;
889
890     if( !fp ) {
891         fp = fopen("armor.out", "w");
892         assert(fp);
893     }
894   #endif
895
896     if( DBG_FILTER )
897         log_debug("armor-filter: control: %d\n", control );
898     if( control == IOBUFCTRL_UNDERFLOW && afx->inp_bypass ) {
899         for( n=0; n < size; n++ ) {
900             if( (c=iobuf_get(a)) == -1 )
901                 break;
902             buf[n] = c & 0xff;
903         }
904         if( !n )
905             rc = -1;
906         *ret_len = n;
907     }
908     else if( control == IOBUFCTRL_UNDERFLOW ) {
909         if( size < 15+(4*15) )  /* need space for up to 4 onepass_sigs */
910             BUG(); /* supplied buffer too short */
911
912         if( afx->inp_eof ) {
913             *ret_len = 0;
914             if( DBG_FILTER )
915                 log_debug("armor-filter: eof due to inp_eof flag\n" );
916             return -1;
917         }
918
919         if( afx->faked )
920             rc = fake_packet( afx, a, &n, buf, size );
921         else if( !afx->inp_checked ) {
922             rc = check_input( afx, a );
923             if( afx->inp_bypass ) {
924                 for( n=0; n < size && n < afx->helplen; n++ )
925                     buf[n] = afx->helpbuf[n];
926                 if( !n )
927                     rc = -1;
928                 assert( n == afx->helplen );
929                 afx->helplen = 0;
930             }
931             else if( afx->faked ) {
932                 unsigned hashes = afx->hashes;
933                 /* the buffer is at least 15+n*15 bytes long, so it
934                  * is easy to construct the packets */
935
936                 hashes &= 1|2|4|8;
937                 if( !hashes )
938                     hashes |= 4;  /* default to MD 5 */
939                 n=0;
940                 do {
941                     /* first some onepass signature packets */
942                     buf[n++] = 0x90; /* old format, type 4, 1 length byte */
943                     buf[n++] = 13;   /* length */
944                     buf[n++] = 3;    /* version */
945                     buf[n++] = 0x01; /* sigclass 0x01 (canonical text mode)*/
946                     if( hashes & 1 ) {
947                         hashes &= ~1;
948                         buf[n++] = DIGEST_ALGO_RMD160;
949                     }
950                     else if( hashes & 2 ) {
951                         hashes &= ~2;
952                         buf[n++] = DIGEST_ALGO_SHA1;
953                     }
954                     else if( hashes & 4 ) {
955                         hashes &= ~4;
956                         buf[n++] = DIGEST_ALGO_MD5;
957                     }
958                     else if( hashes & 8 ) {
959                         hashes &= ~8;
960                         buf[n++] = DIGEST_ALGO_TIGER;
961                     }
962                     else
963                         buf[n++] = 0;    /* (don't know) */
964
965                     buf[n++] = 0;    /* public key algo (don't know) */
966                     memset(buf+n, 0, 8); /* don't know the keyid */
967                     n += 8;
968                     buf[n++] = !hashes;   /* last one */
969                 } while( hashes );
970
971                 /* followed by a plaintext packet */
972                 buf[n++] = 0xaf; /* old packet format, type 11, var length */
973                 buf[n++] = 0;    /* set the length header */
974                 buf[n++] = 6;
975                 buf[n++] = 't';  /* canonical text mode */
976                 buf[n++] = 0;    /* namelength */
977                 memset(buf+n, 0, 4); /* timestamp */
978                 n += 4;
979             }
980             else if( !rc )
981                 rc = radix64_read( afx, a, &n, buf, size );
982         }
983         else
984             rc = radix64_read( afx, a, &n, buf, size );
985       #if 0
986         if( n )
987             if( fwrite(buf, n, 1, fp ) != 1 )
988                 BUG();
989       #endif
990         *ret_len = n;
991     }
992     else if( control == IOBUFCTRL_FLUSH ) {
993         if( !afx->status ) { /* write the header line */
994             if( afx->what >= DIM(head_strings) )
995                 log_bug("afx->what=%d", afx->what);
996             iobuf_writestr(a, "-----");
997             iobuf_writestr(a, head_strings[afx->what] );
998             iobuf_writestr(a, "-----\n");
999             iobuf_writestr(a, "Version: GNUPG v"  VERSION " ("
1000                                             PRINTABLE_OS_NAME ")\n");
1001             iobuf_writestr(a,
1002                 "Comment: Get GNUPG from ftp://ftp.guug.de/pub/gcrypt/\n");
1003             if( afx->hdrlines )
1004                 iobuf_writestr(a, afx->hdrlines);
1005             iobuf_put(a, '\n');
1006             afx->status++;
1007             afx->idx = 0;
1008             afx->idx2 = 0;
1009             afx->crc = CRCINIT;
1010         }
1011         crc = afx->crc;
1012         idx = afx->idx;
1013         idx2 = afx->idx2;
1014         for(i=0; i < idx; i++ )
1015             radbuf[i] = afx->radbuf[i];
1016
1017         for(i=0; i < size; i++ )
1018             crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]];
1019         crc &= 0x00ffffff;
1020
1021         for( ; size; buf++, size-- ) {
1022             radbuf[idx++] = *buf;
1023             if( idx > 2 ) {
1024                 idx = 0;
1025                 c = bintoasc[(*radbuf >> 2) & 077];
1026                 iobuf_put(a, c);
1027                 c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
1028                 iobuf_put(a, c);
1029                 c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
1030                 iobuf_put(a, c);
1031                 c = bintoasc[radbuf[2]&077];
1032                 iobuf_put(a, c);
1033                 if( ++idx2 >= (72/4) ) {
1034                     iobuf_put(a, '\n');
1035                     idx2=0;
1036                 }
1037             }
1038         }
1039         for(i=0; i < idx; i++ )
1040             afx->radbuf[i] = radbuf[i];
1041         afx->idx = idx;
1042         afx->idx2 = idx2;
1043         afx->crc  = crc;
1044     }
1045     else if( control == IOBUFCTRL_INIT ) {
1046         if( !is_initialized )
1047             initialize();
1048     }
1049     else if( control == IOBUFCTRL_FREE ) {
1050         if( afx->status ) { /* pad, write cecksum, and bottom line */
1051             crc = afx->crc;
1052             idx = afx->idx;
1053             idx2 = afx->idx2;
1054             for(i=0; i < idx; i++ )
1055                 radbuf[i] = afx->radbuf[i];
1056             if( idx ) {
1057                 c = bintoasc[(*radbuf>>2)&077];
1058                 iobuf_put(a, c);
1059                 if( idx == 1 ) {
1060                     c = bintoasc[((*radbuf << 4) & 060) & 077];
1061                     iobuf_put(a, c);
1062                     iobuf_put(a, '=');
1063                     iobuf_put(a, '=');
1064                 }
1065                 else { /* 2 */
1066                     c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
1067                     iobuf_put(a, c);
1068                     c = bintoasc[((radbuf[1] << 2) & 074) & 077];
1069                     iobuf_put(a, c);
1070                     iobuf_put(a, '=');
1071                 }
1072                 if( ++idx2 >= (72/4) ) {
1073                     iobuf_put(a, '\n');
1074                     idx2=0;
1075                 }
1076             }
1077             /* may need a linefeed */
1078             if( idx2 )
1079                 iobuf_put(a, '\n');
1080             /* write the CRC */
1081             iobuf_put(a, '=');
1082             radbuf[0] = crc >>16;
1083             radbuf[1] = crc >> 8;
1084             radbuf[2] = crc;
1085             c = bintoasc[(*radbuf >> 2) & 077];
1086             iobuf_put(a, c);
1087             c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
1088             iobuf_put(a, c);
1089             c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
1090             iobuf_put(a, c);
1091             c = bintoasc[radbuf[2]&077];
1092             iobuf_put(a, c);
1093             iobuf_put(a, '\n');
1094             /* and the the trailer */
1095             if( afx->what >= DIM(tail_strings) )
1096                 log_bug("afx->what=%d", afx->what);
1097             iobuf_writestr(a, "-----");
1098             iobuf_writestr(a, tail_strings[afx->what] );
1099             iobuf_writestr(a, "-----\n");
1100         }
1101     }
1102     else if( control == IOBUFCTRL_DESC )
1103         *(char**)buf = "armor_filter";
1104     return rc;
1105 }
1106
1107
1108