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