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