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