/[winpt]/trunk/Gnupg/armor.c
ViewVC logotype

Diff of /trunk/Gnupg/armor.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2 by twoaday, Mon Jan 31 11:02:21 2005 UTC revision 46 by werner, Fri Oct 28 12:57:05 2005 UTC
# Line 1  Line 1 
1  /* armor.c - Armor filter  /* armor.c - Armor filter
2   * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.   * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3   *   *
4   * This file is part of GnuPG.   * This file is part of GnuPG.
5   *   *
6   * GnuPG is free software; you can redistribute it and/or modify   * 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   * 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   * the Free Software Foundation; either version 2 of the License, or
9   * (at your option) any later version.   * (at your option) any later version.
10   *   *
11   * GnuPG is distributed in the hope that it will be useful,   * GnuPG is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.   * GNU General Public License for more details.
15   *   *
16   * You should have received a copy of the GNU General Public License   * You should have received a copy of the GNU General Public License
17   * along with this program; if not, write to the Free Software   * along with this program; if not, write to the Free Software
18   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19   */   */
20    
21  #include <stdio.h>  #ifdef HAVE_CONFIG_H
22  #include <stdlib.h>  #include <config.h>
23  #include <string.h>  #endif
24  #include <errno.h>  
25  #include <ctype.h>  #include <stdio.h>
26  #include <windows.h>  #include <stdio.h>
27  #include <sys/types.h>  #include <stdlib.h>
28    #include <string.h>
29  #include "openpgp.h"  #include <errno.h>
30  #include "packet.h"  #include <ctype.h>
31    #include <windows.h>
32  #define LF "\r\n"  #include <sys/types.h>
33    
34  #define MAX_LINELEN 20000  #include "openpgp.h"
35    #include "packet.h"
36  #define CRCINIT 0xB704CE  
37  #define CRCPOLY 0X864CFB  #define LF "\r\n"
38  #define CRCUPDATE(a,c) do {                                                 \  
39                          a = ((a) << 8) ^ crc_table[((a)&0xff >> 16) ^ (c)]; \  #define MAX_LINELEN 20000
40                          a &= 0x00ffffff;                                    \  
41                      } while(0)  #define CRCINIT 0xB704CE
42  static u32 crc_table[256];  #define CRCPOLY 0X864CFB
43  static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"  #define CRCUPDATE(a,c) do {                                                 \
44                           "abcdefghijklmnopqrstuvwxyz"                          a = ((a) << 8) ^ crc_table[((a)&0xff >> 16) ^ (c)]; \
45                           "0123456789+/";                          a &= 0x00ffffff;                                    \
46  static byte asctobin[256]; /* runtime initialized */                      } while(0)
47  static int is_initialized;  static u32 crc_table[256];
48  static int armor_errno = 0;  static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
49  static char armor_error[256];                           "abcdefghijklmnopqrstuvwxyz"
50                             "0123456789+/";
51  typedef enum {  static byte asctobin[256]; /* runtime initialized */
52      fhdrHASArmor = 0,  static int is_initialized;
53      fhdrNOArmor,  static int armor_errno = 0;
54      fhdrINIT,  static char armor_error[256];
55      fhdrINITCont,  
56      fhdrINITSkip,  typedef enum {
57      fhdrCHECKBegin,      fhdrHASArmor = 0,
58      fhdrWAITHeader,      fhdrNOArmor,
59      fhdrWAITClearsig,      fhdrINIT,
60      fhdrSKIPHeader,      fhdrINITCont,
61      fhdrCLEARSIG,      fhdrINITSkip,
62      fhdrREADClearsig,      fhdrCHECKBegin,
63      fhdrNullClearsig,      fhdrWAITHeader,
64      fhdrEMPTYClearsig,      fhdrWAITClearsig,
65      fhdrCHECKClearsig,      fhdrSKIPHeader,
66      fhdrCHECKClearsig2,      fhdrCLEARSIG,
67      fhdrCHECKDashEscaped,      fhdrREADClearsig,
68      fhdrCHECKDashEscaped2,      fhdrNullClearsig,
69      fhdrCHECKDashEscaped3,      fhdrEMPTYClearsig,
70      fhdrREADClearsigNext,      fhdrCHECKClearsig,
71      fhdrENDClearsig,      fhdrCHECKClearsig2,
72      fhdrENDClearsigHelp,      fhdrCHECKDashEscaped,
73      fhdrTESTSpaces,      fhdrCHECKDashEscaped2,
74      fhdrCLEARSIGSimple,      fhdrCHECKDashEscaped3,
75      fhdrCLEARSIGSimpleNext,      fhdrREADClearsigNext,
76      fhdrTEXT,      fhdrENDClearsig,
77      fhdrTEXTSimple,      fhdrENDClearsigHelp,
78      fhdrERROR,      fhdrTESTSpaces,
79      fhdrERRORShow,      fhdrCLEARSIGSimple,
80      fhdrEOF      fhdrCLEARSIGSimpleNext,
81  } fhdr_state_t;      fhdrTEXT,
82        fhdrTEXTSimple,
83        fhdrERROR,
84  /* if we encounter this armor string with this index, go      fhdrERRORShow,
85   * into a mode which fakes packets and wait for the next armor */      fhdrEOF
86  #define BEGIN_SIGNATURE 2  } fhdr_state_t;
87  #define BEGIN_SIGNED_MSG_IDX 3  
88  static char *head_strings[] = {  
89      "BEGIN PGP MESSAGE",  /* if we encounter this armor string with this index, go
90      "BEGIN PGP PUBLIC KEY BLOCK",   * into a mode which fakes packets and wait for the next armor */
91      "BEGIN PGP SIGNATURE",  #define BEGIN_SIGNATURE 2
92      "BEGIN PGP SIGNED MESSAGE",  #define BEGIN_SIGNED_MSG_IDX 3
93      "BEGIN PGP ARMORED FILE",       /* gnupg extension */  static char *head_strings[] = {
94      "BEGIN PGP PRIVATE KEY BLOCK",      "BEGIN PGP MESSAGE",
95      "BEGIN PGP SECRET KEY BLOCK",   /* only used by pgp2 */      "BEGIN PGP PUBLIC KEY BLOCK",
96      NULL      "BEGIN PGP SIGNATURE",
97  };      "BEGIN PGP SIGNED MESSAGE",
98  static char *tail_strings[] = {      "BEGIN PGP ARMORED FILE",       /* gnupg extension */
99      "END PGP MESSAGE",      "BEGIN PGP PRIVATE KEY BLOCK",
100      "END PGP PUBLIC KEY BLOCK",      "BEGIN PGP SECRET KEY BLOCK",   /* only used by pgp2 */
101      "END PGP SIGNATURE",      NULL
102      "END dummy",  };
103      "END PGP ARMORED FILE",  static char *tail_strings[] = {
104      "END PGP PRIVATE KEY BLOCK",      "END PGP MESSAGE",
105      "END PGP SECRET KEY BLOCK",      "END PGP PUBLIC KEY BLOCK",
106      NULL      "END PGP SIGNATURE",
107  };      "END dummy",
108        "END PGP ARMORED FILE",
109  static void      "END PGP PRIVATE KEY BLOCK",
110  set_armor_error( const char *msg )      "END PGP SECRET KEY BLOCK",
111  {      NULL
112      armor_errno = 1;  };
113      strcpy( armor_error, msg );  
114  }  static void
115    set_armor_error( const char *msg )
116  const char*  {
117  get_armor_error( void )      armor_errno = 1;
118  {      strcpy( armor_error, msg );
119      if( armor_errno )  }
120          return armor_error;  
121      return NULL;  const char*
122  }  get_armor_error( void )
123    {
124        if( armor_errno )
125  static unsigned int          return armor_error;
126  check_trailing_chars( const byte *line, unsigned int len,      return NULL;
127                        const char *trimchars )  }
128  {  
129      const byte *p, *mark;  
130      unsigned int n;  static unsigned int
131        check_trailing_chars( const byte *line, unsigned int len,
132      for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {                        const char *trimchars )
133          if( strchr(trimchars, *p ) ) {  {
134              if( !mark )      const byte *p, *mark;
135                  mark = p;      unsigned int n;
136          }      
137          else      for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
138              mark = NULL;          if( strchr(trimchars, *p ) ) {
139      }              if( !mark )
140                        mark = p;
141      if( mark ) {          }
142          return mark - line;          else
143      }              mark = NULL;
144      return len;      }
145  }      
146        if( mark ) {
147  /****************          return mark - line;
148   * remove trailing white spaces and return the length of the buffer      }
149   */      return len;
150  static unsigned int  }
151  check_trailing_ws( const byte *line, unsigned int len )  
152  {  /****************
153      return check_trailing_chars( line, len, " \t\r\n" );   * remove trailing white spaces and return the length of the buffer
154  }   */
155    static unsigned int
156  static unsigned int  check_trailing_ws( const byte *line, unsigned int len )
157  trim_trailing_chars( byte *line, unsigned len, const char *trimchars )  {
158  {      return check_trailing_chars( line, len, " \t\r\n" );
159      byte *p, *mark;  }
160      unsigned n;  
161        static unsigned int
162      for( mark=NULL, p=line, n=0; n < len; n++, p++ ) {  trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
163          if( strchr(trimchars, *p ) ) {  {
164              if( !mark )      byte *p, *mark;
165                  mark = p;      unsigned n;
166          }      
167          else      for( mark=NULL, p=line, n=0; n < len; n++, p++ ) {
168              mark = NULL;          if( strchr(trimchars, *p ) ) {
169      }              if( !mark )
170                        mark = p;
171      if( mark ) {          }
172          *mark = 0;          else
173          return mark - line;              mark = NULL;
174      }      }
175      return len;      
176  }      if( mark ) {
177            *mark = 0;
178  static void          return mark - line;
179  initialize(void)      }
180  {      return len;
181      int i, j;  }
182      u32 t;  
183      byte *s;  static void
184        initialize(void)
185      /* init the crc lookup table */  {
186      crc_table[0] = 0;      int i, j;
187      for( i=j=0; j < 128; j++ ) {      u32 t;
188          t = crc_table[j];      byte *s;
189          if( t & 0x00800000 ) {      
190              t <<= 1;      /* init the crc lookup table */
191              crc_table[i++] = t ^ CRCPOLY;      crc_table[0] = 0;
192              crc_table[i++] = t;      for( i=j=0; j < 128; j++ ) {
193          }          t = crc_table[j];
194          else {          if( t & 0x00800000 ) {
195              t <<= 1;              t <<= 1;
196              crc_table[i++] = t;              crc_table[i++] = t ^ CRCPOLY;
197              crc_table[i++] = t ^ CRCPOLY;              crc_table[i++] = t;
198          }          }
199      }          else {
200      /* build the helptable for radix64 to bin conversion */              t <<= 1;
201      for( i = 0; i < 256; i++ )              crc_table[i++] = t;
202          asctobin[i] = 255; /* used to detect invalid characters */              crc_table[i++] = t ^ CRCPOLY;
203      for( s = bintoasc, i = 0; *s; s++,i++ )          }
204          asctobin[*s] = i;      }
205            /* build the helptable for radix64 to bin conversion */
206      is_initialized=1;      for( i = 0; i < 256; i++ )
207  }          asctobin[i] = 255; /* used to detect invalid characters */
208        for( s = bintoasc, i = 0; *s; s++,i++ )
209  /****************          asctobin[*s] = i;
210   * Check whether this is an armored file or not See also      
211   * parse-packet.c for details on this code For unknown historic      is_initialized=1;
212   * reasons we use a string here but only the first byte will be used.  }
213   * Returns: True if it seems to be armored  
214   */  /****************
215  static int   * Check whether this is an armored file or not See also
216  is_armored( const byte *buf )   * parse-packet.c for details on this code For unknown historic
217  {   * reasons we use a string here but only the first byte will be used.
218      int ctb, pkttype;   * Returns: True if it seems to be armored
219         */
220      ctb = *buf;  static int
221      if( !(ctb & 0x80) )  is_armored( const byte *buf )
222          return 1; /* invalid packet: assume it is armored */  {
223      pkttype =  ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf);      int ctb, pkttype;
224      switch( pkttype ) {      
225      case PKT_MARKER:      ctb = *buf;
226      case PKT_SYMKEY_ENC:      if( !(ctb & 0x80) )
227      case PKT_ONEPASS_SIG:          return 1; /* invalid packet: assume it is armored */
228      case PKT_PUBLIC_KEY:      pkttype =  ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf);
229      case PKT_SECRET_KEY:      switch( pkttype ) {
230      case PKT_PUBKEY_ENC:      case PKT_MARKER:
231      case PKT_SIGNATURE:      case PKT_SYMKEY_ENC:
232      case PKT_COMMENT:      case PKT_ONEPASS_SIG:
233      case PKT_OLD_COMMENT:      case PKT_PUBLIC_KEY:
234      case PKT_PLAINTEXT:      case PKT_SECRET_KEY:
235      case PKT_COMPRESSED:      case PKT_PUBKEY_ENC:
236      case PKT_ENCRYPTED:      case PKT_SIGNATURE:
237          return 0; /* seems to be a regular packet: not armored */      case PKT_COMMENT:
238      }      case PKT_OLD_COMMENT:
239            case PKT_PLAINTEXT:
240      return 1;      case PKT_COMPRESSED:
241  }      case PKT_ENCRYPTED:
242            return 0; /* seems to be a regular packet: not armored */
243        }
244  /****************      
245   * Try to check whether the iobuf is armored      return 1;
246   * Returns true if this may be the case; the caller should use the  }
247   *         filter to do further processing.  
248   */  
249  int  /****************
250  gpg_use_armor_filter( gpg_iobuf_t a )   * Try to check whether the iobuf is armored
251  {   * Returns true if this may be the case; the caller should use the
252      byte buf[1];   *         filter to do further processing.
253      int n;   */
254        int
255      /* fixme: there might be a problem with iobuf_peek */  gpg_use_armor_filter( gpg_iobuf_t a )
256      n = gpg_iobuf_peek(a, buf, 1 );  {
257      if( n == -1 )      byte buf[1];
258          return 0; /* EOF, doesn't matter whether armored or not */      int n;
259      if( !n )      
260          return 1; /* can't check it: try armored */      /* fixme: there might be a problem with iobuf_peek */
261      return is_armored(buf);      n = gpg_iobuf_peek(a, buf, 1 );
262  }      if( n == -1 )
263            return 0; /* EOF, doesn't matter whether armored or not */
264  /****************      if( !n )
265   * check whether the armor header is valid on a signed message.          return 1; /* can't check it: try armored */
266   * this is for security reasons: the header lines are not included in the      return is_armored(buf);
267   * hash and by using some creative formatting rules, Mallory could fake  }
268   * any text at the beginning of a document; assuming it is read with  
269   * a simple viewer. We only allow the Hash Header.  /****************
270   */   * check whether the armor header is valid on a signed message.
271  static int   * this is for security reasons: the header lines are not included in the
272  parse_hash_header( const char *line )   * hash and by using some creative formatting rules, Mallory could fake
273  {   * any text at the beginning of a document; assuming it is read with
274      const char *s, *s2;   * a simple viewer. We only allow the Hash Header.
275      unsigned found = 0;   */
276        static int
277      if( strlen(line) < 6  || strlen(line) > 60 )  parse_hash_header( const char *line )
278          return 0; /* too short or too long */  {
279      if( memcmp( line, "Hash:", 5 ) )      const char *s, *s2;
280          return 0; /* invalid header */      unsigned found = 0;
281      s = line+5;      
282      for( s = line + 5; ; s=s2 ) {      if( strlen(line) < 6  || strlen(line) > 60 )
283          for(; *s && (*s==' ' || *s == '\t'); s++ )          return 0; /* too short or too long */
284              ;      if( memcmp( line, "Hash:", 5 ) )
285          if( !*s )          return 0; /* invalid header */
286              break;      s = line+5;
287          for(s2=s+1; *s2 && *s2!=' ' && *s2 != '\t' && *s2 != ','; s2++ )      for( s = line + 5; ; s=s2 ) {
288              ;          for(; *s && (*s==' ' || *s == '\t'); s++ )
289          if( !strncmp( s, "RIPEMD160", s2-s ) )              ;
290              found |= 1;          if( !*s )
291          else if( !strncmp( s, "SHA1", s2-s ) )              break;
292              found |= 2;          for(s2=s+1; *s2 && *s2!=' ' && *s2 != '\t' && *s2 != ','; s2++ )
293          else if( !strncmp( s, "MD5", s2-s ) )              ;
294              found |= 4;          if( !strncmp( s, "RIPEMD160", s2-s ) )
295          else if( !strncmp( s, "TIGER192", s2-s ) )              found |= 1;
296              found |= 8;          else if( !strncmp( s, "SHA1", s2-s ) )
297          else if( !strncmp( s, "TIGER", s2-s ) ) /* used by old versions */              found |= 2;
298              found |= 8;          else if( !strncmp( s, "MD5", s2-s ) )
299          else              found |= 4;
300              return 0;          else if( !strncmp( s, "TIGER192", s2-s ) )
301          for(; *s2 && (*s2==' ' || *s2 == '\t'); s2++ )              found |= 8;
302              ;          else if( !strncmp( s, "TIGER", s2-s ) ) /* used by old versions */
303          if( *s2 && *s2 != ',' )              found |= 8;
304              return 0;          else
305          if( *s2 )              return 0;
306              s2++;          for(; *s2 && (*s2==' ' || *s2 == '\t'); s2++ )
307      }              ;
308      return found;          if( *s2 && *s2 != ',' )
309  }              return 0;
310            if( *s2 )
311                s2++;
312        }
313  /****************      return found;
314   * Check whether this is a armor line.  }
315   * returns: -1 if it is not a armor header or the index number of the  
316   * armor header.  
317   */  
318  static int  /****************
319  is_armor_header( byte *line, unsigned len )   * Check whether this is a armor line.
320  {   * returns: -1 if it is not a armor header or the index number of the
321      const char *s;   * armor header.
322      byte *save_p, *p;   */
323      int save_c;  static int
324      int i;  is_armor_header( byte *line, unsigned len )
325        {
326      if( len < 15 )      const char *s;
327          return -1; /* too short */      byte *save_p, *p;
328      if( memcmp( line, "-----", 5 ) )      int save_c;
329          return -1; /* no */      int i;
330      p = strstr( line+5, "-----");      
331      if( !p )      if( len < 15 )
332          return -1;          return -1; /* too short */
333      save_p = p;      if( memcmp( line, "-----", 5 ) )
334      p += 5;          return -1; /* no */
335            p = strstr( line+5, "-----");
336      /* Some mail programs on Windows seem to add spaces to the end of      if( !p )
337         the line.  This becomes strict if --openpgp is set. */          return -1;
338            save_p = p;
339  #if 0      p += 5;
340      if(!opt.rfc2440)      
341          while(*p==' ')      /* Some mail programs on Windows seem to add spaces to the end of
342              p++;         the line.  This becomes strict if --openpgp is set. */
343  #endif      
344        #if 0
345      if( *p == '\r' )      if(!opt.rfc2440)
346          p++;          while(*p==' ')
347      if( *p == '\n' )              p++;
348          p++;  #endif
349      if( *p )      
350          return -1; /* garbage after dashes */      if( *p == '\r' )
351      save_c = *save_p; *save_p = 0;          p++;
352      p = line+5;      if( *p == '\n' )
353      for(i=0; (s=head_strings[i]); i++ )          p++;
354          if( !strcmp(s, p) )      if( *p )
355              break;          return -1; /* garbage after dashes */
356      *save_p = save_c;      save_c = *save_p; *save_p = 0;
357      if( !s )      p = line+5;
358          return -1; /* unknown armor line */      for(i=0; (s=head_strings[i]); i++ )
359                if( !strcmp(s, p) )
360      return i;              break;
361  }      *save_p = save_c;
362        if( !s )
363  void          return -1; /* unknown armor line */
364  print_string( FILE *fp, const byte *p, size_t n, int delim )      
365  {      return i;
366      for( ; n; n--, p++ )  }
367          if( *p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim ||  
368              (delim && *p=='\\')) {  void
369              putc('\\', fp);  print_string( FILE *fp, const byte *p, size_t n, int delim )
370              if( *p == '\n' )  {
371                  putc('n', fp);      for( ; n; n--, p++ )
372              else if( *p == '\r' )          if( *p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim ||
373                  putc('r', fp);              (delim && *p=='\\')) {
374              else if( *p == '\f' )              putc('\\', fp);
375                  putc('f', fp);              if( *p == '\n' )
376              else if( *p == '\v' )                  putc('n', fp);
377                  putc('v', fp);              else if( *p == '\r' )
378              else if( *p == '\b' )                  putc('r', fp);
379                  putc('b', fp);              else if( *p == '\f' )
380              else if( !*p )                  putc('f', fp);
381                  putc('0', fp);              else if( *p == '\v' )
382              else                  putc('v', fp);
383                  fprintf(fp, "x%02x", *p );              else if( *p == '\b' )
384          }                  putc('b', fp);
385          else              else if( !*p )
386              putc(*p, fp);                  putc('0', fp);
387  }              else
388                    fprintf(fp, "x%02x", *p );
389  /****************          }
390   * Parse a header lines          else
391   * Return 0: Empty line (end of header lines)              putc(*p, fp);
392   *       -1: invalid header line  }
393   *       >0: Good header line  
394   */  /****************
395  static int   * Parse a header lines
396  parse_header_line( armor_filter_context_t *afx, byte *line, unsigned int len )   * Return 0: Empty line (end of header lines)
397  {   *       -1: invalid header line
398      byte *p;   *       >0: Good header line
399      int hashes=0;   */
400      unsigned int len2;  static int
401        parse_header_line( armor_filter_context_t *afx, byte *line, unsigned int len )
402      len2 = check_trailing_ws( line, len );  {
403      if( !len2 ) {      byte *p;
404          afx->buffer_pos = len2;  /* (it is not the fine way to do it here) */      int hashes=0;
405          return 0; /* WS only: same as empty line */      unsigned int len2;
406      }      
407      len = len2;      len2 = check_trailing_ws( line, len );
408      line[len2] = 0;      if( !len2 ) {
409                afx->buffer_pos = len2;  /* (it is not the fine way to do it here) */
410      p = strchr( line, ':');          return 0; /* WS only: same as empty line */
411      if( !p || !p[1] ) {      }
412          set_armor_error("invalid armor header: ");      len = len2;
413          print_string( stderr, line, len, 0 );      line[len2] = 0;
414          putc('\n', stderr);      
415          return -1;      p = strchr( line, ':');
416      }          if( !p || !p[1] ) {
417                set_armor_error("invalid armor header: ");
418      if( afx->in_cleartext ) {          print_string( stderr, line, len, 0 );
419          if( (hashes=parse_hash_header( line )) )          putc('\n', stderr);
420              afx->hashes |= hashes;          return -1;
421          else if( strlen(line) > 15 && !memcmp( line, "NotDashEscaped:", 15 ) )      }    
422              afx->not_dash_escaped = 1;      
423          else {      if( afx->in_cleartext ) {
424              set_armor_error("invalid clearsig header\n");          if( (hashes=parse_hash_header( line )) )
425              return -1;              afx->hashes |= hashes;
426          }          else if( strlen(line) > 15 && !memcmp( line, "NotDashEscaped:", 15 ) )
427      }              afx->not_dash_escaped = 1;
428      return 1;          else {
429  }              set_armor_error("invalid clearsig header\n");
430                return -1;
431            }
432        }
433  /* figure out whether the data is armored or not */      return 1;
434  static int  }
435  check_input( armor_filter_context_t *afx, gpg_iobuf_t a )  
436  {  
437      int rc = 0;  
438      int i;  /* figure out whether the data is armored or not */
439      byte *line;  static int
440      unsigned len;  check_input( armor_filter_context_t *afx, gpg_iobuf_t a )
441      unsigned maxlen;  {
442      int hdr_line = -1;      int rc = 0;
443            int i;
444      /* read the first line to see whether this is armored data */      byte *line;
445      maxlen = MAX_LINELEN;      unsigned len;
446      len = afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,      unsigned maxlen;
447                                               &afx->buffer_size, &maxlen );      int hdr_line = -1;
448      line = afx->buffer;      
449      if( !maxlen ) {      /* read the first line to see whether this is armored data */
450          /* line has been truncated: assume not armored */      maxlen = MAX_LINELEN;
451          afx->inp_checked = 1;      len = afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,
452          afx->inp_bypass = 1;                                               &afx->buffer_size, &maxlen );
453          return 0;      line = afx->buffer;
454      }      if( !maxlen ) {
455                /* line has been truncated: assume not armored */
456      if( !len ) {          afx->inp_checked = 1;
457          return -1; /* eof */          afx->inp_bypass = 1;
458      }          return 0;
459            }
460      /* (the line is always a C string but maybe longer) */      
461      if( *line == '\n' || ( len && (*line == '\r' && line[1]=='\n') ) )      if( !len ) {
462          ;          return -1; /* eof */
463      else if( !is_armored( line ) ) {      }
464          afx->inp_checked = 1;      
465          afx->inp_bypass = 1;      /* (the line is always a C string but maybe longer) */
466          return 0;      if( *line == '\n' || ( len && (*line == '\r' && line[1]=='\n') ) )
467      }          ;
468            else if( !is_armored( line ) ) {
469      /* find the armor header */          afx->inp_checked = 1;
470      while(len) {          afx->inp_bypass = 1;
471          i = is_armor_header( line, len );          return 0;
472          if( i >= 0 && !(afx->only_keyblocks && i != 1 && i != 5 && i != 6 )) {      }
473              hdr_line = i;      
474              if( hdr_line == BEGIN_SIGNED_MSG_IDX ) {      /* find the armor header */
475                  if( afx->in_cleartext ) {      while(len) {
476                      set_armor_error("nested clear text signatures\n");          i = is_armor_header( line, len );
477                      rc = G10ERR_INVALID_ARMOR;          if( i >= 0 && !(afx->only_keyblocks && i != 1 && i != 5 && i != 6 )) {
478                  }              hdr_line = i;
479                  afx->in_cleartext = 1;              if( hdr_line == BEGIN_SIGNED_MSG_IDX ) {
480              }                  if( afx->in_cleartext ) {
481              break;                      set_armor_error("nested clear text signatures\n");
482          }                      rc = G10ERR_INVALID_ARMOR;
483          /* read the next line (skip all truncated lines) */                  }
484          do {                  afx->in_cleartext = 1;
485              maxlen = MAX_LINELEN;              }
486              afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,              break;
487                                                 &afx->buffer_size, &maxlen );          }
488              line = afx->buffer;          /* read the next line (skip all truncated lines) */
489              len = afx->buffer_len;          do {
490          } while( !maxlen );              maxlen = MAX_LINELEN;
491      }              afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,
492                                                       &afx->buffer_size, &maxlen );
493      /* parse the header lines */              line = afx->buffer;
494      while(len) {              len = afx->buffer_len;
495          /* read the next line (skip all truncated lines) */          } while( !maxlen );
496          do {      }
497              maxlen = MAX_LINELEN;      
498              afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,      /* parse the header lines */
499                                                 &afx->buffer_size, &maxlen );      while(len) {
500              line = afx->buffer;          /* read the next line (skip all truncated lines) */
501              len = afx->buffer_len;          do {
502          } while( !maxlen );              maxlen = MAX_LINELEN;
503                        afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,
504          i = parse_header_line( afx, line, len );                                                 &afx->buffer_size, &maxlen );
505          if( i <= 0 ) {              line = afx->buffer;
506              if( i )              len = afx->buffer_len;
507                  rc = G10ERR_INVALID_ARMOR;          } while( !maxlen );
508              break;          
509          }          i = parse_header_line( afx, line, len );
510      }          if( i <= 0 ) {
511                if( i )
512      if( afx->in_cleartext )                  rc = G10ERR_INVALID_ARMOR;
513          afx->faked = 1;              break;
514      else {          }
515          afx->inp_checked = 1;      }
516          afx->crc = CRCINIT;  
517          afx->idx = 0;      if( afx->in_cleartext )
518          afx->radbuf[0] = 0;          afx->faked = 1;
519      }      else {
520                afx->inp_checked = 1;
521      return rc;          afx->crc = CRCINIT;
522  }          afx->idx = 0;
523            afx->radbuf[0] = 0;
524        }
525        
526  /****************      return rc;
527   * Fake a literal data packet and wait for the next armor line  }
528   * fixme: empty line handling and null length clear text signature are  
529   *        not implemented/checked.  
530   */  
531  static int  /****************
532  fake_packet( armor_filter_context_t *afx, gpg_iobuf_t a,   * Fake a literal data packet and wait for the next armor line
533               size_t *retn, byte *buf, size_t size  )   * fixme: empty line handling and null length clear text signature are
534  {   *        not implemented/checked.
535      int rc = 0;   */
536      size_t len = 0;  static int
537      int lastline = 0;  fake_packet( armor_filter_context_t *afx, gpg_iobuf_t a,
538      unsigned maxlen, n;               size_t *retn, byte *buf, size_t size  )
539      byte *p;  {
540            int rc = 0;
541      len = 2;    /* reserve 2 bytes for the length header */      size_t len = 0;
542      size -= 2;  /* and 2 for the terminating header */      int lastline = 0;
543      while( !rc && len < size ) {      unsigned maxlen, n;
544          /* copy what we have in the line buffer */      byte *p;
545          if( afx->faked == 1 )      
546              afx->faked++; /* skip the first (empty) line */      len = 2;    /* reserve 2 bytes for the length header */
547          else {      size -= 2;  /* and 2 for the terminating header */
548              while( len < size && afx->buffer_pos < afx->buffer_len )      while( !rc && len < size ) {
549                  buf[len++] = afx->buffer[afx->buffer_pos++];          /* copy what we have in the line buffer */
550              if( len >= size )          if( afx->faked == 1 )
551                  continue;              afx->faked++; /* skip the first (empty) line */
552          }          else {
553                        while( len < size && afx->buffer_pos < afx->buffer_len )
554          /* read the next line */                  buf[len++] = afx->buffer[afx->buffer_pos++];
555          maxlen = MAX_LINELEN;              if( len >= size )
556          afx->buffer_pos = 0;                  continue;
557          afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,          }
558                                             &afx->buffer_size, &maxlen );          
559          if( !afx->buffer_len ) {          /* read the next line */
560              rc = -1; /* eof (should not happen) */          maxlen = MAX_LINELEN;
561              continue;          afx->buffer_pos = 0;
562          }          afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,
563          if( !maxlen )                                             &afx->buffer_size, &maxlen );
564              afx->truncated++;          if( !afx->buffer_len ) {
565          if( !afx->not_dash_escaped ) {              rc = -1; /* eof (should not happen) */
566              int crlf;              continue;
567              p = afx->buffer;          }
568              n = afx->buffer_len;          if( !maxlen )
569              crlf = n > 1 && p[n-2] == '\r' && p[n-1]=='\n';              afx->truncated++;
570                        if( !afx->not_dash_escaped ) {
571              /* PGP2 does not treat a tab as white space character */              int crlf;
572              afx->buffer_len = trim_trailing_chars( p, n,              p = afx->buffer;
573                                                     afx->pgp2mode ? " \r\n" : " \t\r\n");              n = afx->buffer_len;
574              /* the buffer is always allocated with enough space to append              crlf = n > 1 && p[n-2] == '\r' && p[n-1]=='\n';
575               * the removed [CR], LF and a Nul              
576               * The reason for this complicated procedure is to keep at least              /* PGP2 does not treat a tab as white space character */
577               * the original type of lineending - handling of the removed              afx->buffer_len = trim_trailing_chars( p, n,
578               * trailing spaces seems to be impossible in our method                                                     afx->pgp2mode ? " \r\n" : " \t\r\n");
579               * of faking a packet; either we have to use a temporary file              /* the buffer is always allocated with enough space to append
580               * or calculate the hash here in this module and somehow find               * the removed [CR], LF and a Nul
581               * a way to send the hash down the processing line (well, a special               * The reason for this complicated procedure is to keep at least
582               * faked packet could do the job).               * the original type of lineending - handling of the removed
583               */               * trailing spaces seems to be impossible in our method
584              if( crlf )               * of faking a packet; either we have to use a temporary file
585                  afx->buffer[afx->buffer_len++] = '\r';               * or calculate the hash here in this module and somehow find
586              afx->buffer[afx->buffer_len++] = '\n';               * a way to send the hash down the processing line (well, a special
587              afx->buffer[afx->buffer_len] = 0;               * faked packet could do the job).
588          }               */
589          p = afx->buffer;              if( crlf )
590          n = afx->buffer_len;                  afx->buffer[afx->buffer_len++] = '\r';
591                        afx->buffer[afx->buffer_len++] = '\n';
592          if( n > 2 && *p == '-' ) {              afx->buffer[afx->buffer_len] = 0;
593              /* check for dash escaped or armor header */          }
594              if( p[1] == ' ' && !afx->not_dash_escaped ) {          p = afx->buffer;
595                  /* issue a warning if it is not regular encoded */          n = afx->buffer_len;
596                  if( p[2] != '-' && !( n > 6 && !memcmp(p+2, "From ", 5))) {          
597                      set_armor_error("invalid dash escaped line: ");          if( n > 2 && *p == '-' ) {
598                      print_string( stderr, p, n, 0 );              /* check for dash escaped or armor header */
599                      putc('\n', stderr);              if( p[1] == ' ' && !afx->not_dash_escaped ) {
600                  }                  /* issue a warning if it is not regular encoded */
601                  afx->buffer_pos = 2; /* skip */                  if( p[2] != '-' && !( n > 6 && !memcmp(p+2, "From ", 5))) {
602              }                      set_armor_error("invalid dash escaped line: ");
603              else if( n >= 15 &&  p[1] == '-' && p[2] == '-' && p[3] == '-' ) {                      print_string( stderr, p, n, 0 );
604                  int type = is_armor_header( p, n );                      putc('\n', stderr);
605                  if( afx->not_dash_escaped && type != BEGIN_SIGNATURE )                  }
606                      ; /* this is okay */                  afx->buffer_pos = 2; /* skip */
607                  else {              }
608                      if( type != BEGIN_SIGNATURE ) {              else if( n >= 15 &&  p[1] == '-' && p[2] == '-' && p[3] == '-' ) {
609                          set_armor_error("unexpected armor:");                  int type = is_armor_header( p, n );
610                          print_string( stderr, p, n, 0 );                  if( afx->not_dash_escaped && type != BEGIN_SIGNATURE )
611                          putc('\n', stderr);                      ; /* this is okay */
612                      }                  else {
613                      lastline = 1;                      if( type != BEGIN_SIGNATURE ) {
614                      rc = -1;                          set_armor_error("unexpected armor:");
615                  }                          print_string( stderr, p, n, 0 );
616              }                          putc('\n', stderr);
617          }                      }
618      }                      lastline = 1;
619                            rc = -1;
620      buf[0] = (len-2) >> 8;                  }
621      buf[1] = (len-2);              }
622      if( lastline ) { /* write last (ending) length header */          }
623          if( buf[0] || buf[1] ) { /* only if we have some text */      }
624              buf[len++] = 0;      
625              buf[len++] = 0;      buf[0] = (len-2) >> 8;
626          }      buf[1] = (len-2);
627          rc = 0;      if( lastline ) { /* write last (ending) length header */
628          afx->faked = 0;          if( buf[0] || buf[1] ) { /* only if we have some text */
629          afx->in_cleartext = 0;              buf[len++] = 0;
630          /* and now read the header lines */              buf[len++] = 0;
631          afx->buffer_pos = 0;          }
632          for(;;) {          rc = 0;
633              int i;          afx->faked = 0;
634                        afx->in_cleartext = 0;
635              /* read the next line (skip all truncated lines) */          /* and now read the header lines */
636              do {          afx->buffer_pos = 0;
637                  maxlen = MAX_LINELEN;          for(;;) {
638                  afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,              int i;
639                                                     &afx->buffer_size, &maxlen );              
640              } while( !maxlen );              /* read the next line (skip all truncated lines) */
641              p = afx->buffer;              do {
642              n = afx->buffer_len;                  maxlen = MAX_LINELEN;
643              if( !n ) {                  afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,
644                  rc = -1;                                                     &afx->buffer_size, &maxlen );
645                  break; /* eof */              } while( !maxlen );
646              }              p = afx->buffer;
647              i = parse_header_line( afx, p , n );              n = afx->buffer_len;
648              if( i <= 0 ) {              if( !n ) {
649                  if( i )                  rc = -1;
650                      MessageBox( NULL, "Invalid ARMOR detected", "Error", MB_OK );                  break; /* eof */
651                  break;              }
652              }              i = parse_header_line( afx, p , n );
653          }              if( i <= 0 ) {
654          afx->inp_checked = 1;                  if( i )
655          afx->crc = CRCINIT;                      MessageBox( NULL, "Invalid ARMOR detected", "Error", MB_OK );
656          afx->idx = 0;                  break;
657          afx->radbuf[0] = 0;              }
658      }          }
659                afx->inp_checked = 1;
660      *retn = len;          afx->crc = CRCINIT;
661      return rc;          afx->idx = 0;
662  }          afx->radbuf[0] = 0;
663        }
664        
665  static int      *retn = len;
666  invalid_crc(void)      return rc;
667  {          }
668      return G10ERR_INVALID_ARMOR;  
669  }  
670    static int
671    invalid_crc(void)
672  static int  {        
673  radix64_read( armor_filter_context_t *afx, gpg_iobuf_t a, size_t *retn,      return G10ERR_INVALID_ARMOR;
674                byte *buf, size_t size )  }
675  {  
676      byte val;  
677      int c=0, c2; /*init c because gcc is not clever enough for the continue*/  static int
678      int checkcrc=0;  radix64_read( armor_filter_context_t *afx, gpg_iobuf_t a, size_t *retn,
679      int rc = 0;                byte *buf, size_t size )
680      size_t n = 0;  {
681      int  idx, i;      byte val;
682      u32 crc;      int c=0, c2; /*init c because gcc is not clever enough for the continue*/
683            int checkcrc=0;
684      crc = afx->crc;      int rc = 0;
685      idx = afx->idx;      size_t n = 0;
686      val = afx->radbuf[0];      int  idx, i;
687      for( n=0; n < size; ) {      u32 crc;
688                
689          if( afx->buffer_pos < afx->buffer_len )      crc = afx->crc;
690              c = afx->buffer[afx->buffer_pos++];      idx = afx->idx;
691          else { /* read the next line */      val = afx->radbuf[0];
692              unsigned maxlen = MAX_LINELEN;      for( n=0; n < size; ) {
693              afx->buffer_pos = 0;          
694              afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,          if( afx->buffer_pos < afx->buffer_len )
695                                                 &afx->buffer_size, &maxlen );              c = afx->buffer[afx->buffer_pos++];
696              if( !maxlen )          else { /* read the next line */
697                  afx->truncated++;              unsigned maxlen = MAX_LINELEN;
698              if( !afx->buffer_len )              afx->buffer_pos = 0;
699                  break; /* eof */              afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,
700              continue;                                                 &afx->buffer_size, &maxlen );
701          }              if( !maxlen )
702                            afx->truncated++;
703      again:              if( !afx->buffer_len )
704          if( c == '\n' || c == ' ' || c == '\r' || c == '\t' )                  break; /* eof */
705              continue;              continue;
706          else if( c == '=' ) { /* pad character: stop */          }
707              /* some mailers leave quoted-printable encoded characters          
708               * so we try to workaround this */      again:
709              if( afx->buffer_pos+2 < afx->buffer_len ) {          if( c == '\n' || c == ' ' || c == '\r' || c == '\t' )
710                  int cc1, cc2, cc3;              continue;
711                  cc1 = afx->buffer[afx->buffer_pos];          else if( c == '=' ) { /* pad character: stop */
712                  cc2 = afx->buffer[afx->buffer_pos+1];              /* some mailers leave quoted-printable encoded characters
713                  cc3 = afx->buffer[afx->buffer_pos+2];               * so we try to workaround this */
714                  if( isxdigit(cc1) && isxdigit(cc2)              if( afx->buffer_pos+2 < afx->buffer_len ) {
715                      && strchr( "=\n\r\t ", cc3 )) {                  int cc1, cc2, cc3;
716                      /* well it seems to be the case - adjust */                  cc1 = afx->buffer[afx->buffer_pos];
717                      c = isdigit(cc1)? (cc1 - '0'): (toupper(cc1)-'A'+10);                  cc2 = afx->buffer[afx->buffer_pos+1];
718                      c <<= 4;                  cc3 = afx->buffer[afx->buffer_pos+2];
719                      c |= isdigit(cc2)? (cc2 - '0'): (toupper(cc2)-'A'+10);                  if( isxdigit(cc1) && isxdigit(cc2)
720                      afx->buffer_pos += 2;                      && strchr( "=\n\r\t ", cc3 )) {
721                      afx->qp_detected = 1;                      /* well it seems to be the case - adjust */
722                      goto again;                      c = isdigit(cc1)? (cc1 - '0'): (toupper(cc1)-'A'+10);
723                  }                      c <<= 4;
724              }                      c |= isdigit(cc2)? (cc2 - '0'): (toupper(cc2)-'A'+10);
725                                    afx->buffer_pos += 2;
726              if( idx == 1 )                      afx->qp_detected = 1;
727                  buf[n++] = val;                      goto again;
728              checkcrc++;                  }
729              break;              }
730          }              
731          else if( (c = asctobin[(c2=c)]) == 255 ) {              if( idx == 1 )
732              char msg[128];                  buf[n++] = val;
733              _snprintf( msg, sizeof msg-1, "invalid radix64 character %02x skipped\n", c2);              checkcrc++;
734              set_armor_error( msg );              break;
735              continue;          }
736          }          else if( (c = asctobin[(c2=c)]) == 255 ) {
737          switch(idx) {              char msg[128];
738          case 0: val =  c << 2; break;              _snprintf( msg, sizeof msg-1, "invalid radix64 character %02x skipped\n", c2);
739          case 1: val |= (c>>4)&3; buf[n++]=val;val=(c<<4)&0xf0;break;              set_armor_error( msg );
740          case 2: val |= (c>>2)&15; buf[n++]=val;val=(c<<6)&0xc0;break;              continue;
741          case 3: val |= c&0x3f; buf[n++] = val; break;          }
742          }          switch(idx) {
743          idx = (idx+1) % 4;          case 0: val =  c << 2; break;
744      }          case 1: val |= (c>>4)&3; buf[n++]=val;val=(c<<4)&0xf0;break;
745                case 2: val |= (c>>2)&15; buf[n++]=val;val=(c<<6)&0xc0;break;
746      for(i=0; i < n; i++ )          case 3: val |= c&0x3f; buf[n++] = val; break;
747          crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]];          }
748      crc &= 0x00ffffff;          idx = (idx+1) % 4;
749      afx->crc = crc;      }
750      afx->idx = idx;      
751      afx->radbuf[0] = val;      for(i=0; i < n; i++ )
752                crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]];
753      if( checkcrc ) {      crc &= 0x00ffffff;
754          afx->any_data = 1;      afx->crc = crc;
755          afx->inp_checked=0;      afx->idx = idx;
756          afx->faked = 0;      afx->radbuf[0] = val;
757          for(;;) { /* skip lf and pad characters */      
758              if( afx->buffer_pos < afx->buffer_len )      if( checkcrc ) {
759                  c = afx->buffer[afx->buffer_pos++];          afx->any_data = 1;
760              else { /* read the next line */          afx->inp_checked=0;
761                  unsigned maxlen = MAX_LINELEN;          afx->faked = 0;
762                  afx->buffer_pos = 0;          for(;;) { /* skip lf and pad characters */
763                  afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,              if( afx->buffer_pos < afx->buffer_len )
764                                                     &afx->buffer_size, &maxlen );                  c = afx->buffer[afx->buffer_pos++];
765                  if( !maxlen )              else { /* read the next line */
766                      afx->truncated++;                  unsigned maxlen = MAX_LINELEN;
767                  if( !afx->buffer_len )                  afx->buffer_pos = 0;
768                      break; /* eof */                  afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,
769                  continue;                                                     &afx->buffer_size, &maxlen );
770              }                  if( !maxlen )
771              if( c == '\n' || c == ' ' || c == '\r'                      afx->truncated++;
772                  || c == '\t' || c == '=' )                  if( !afx->buffer_len )
773                  continue;                      break; /* eof */
774              break;                  continue;
775          }              }
776          if( c == -1 )              if( c == '\n' || c == ' ' || c == '\r'
777              set_armor_error("premature eof (no CRC)\n");                  || c == '\t' || c == '=' )
778          else {                  continue;
779              u32 mycrc = 0;              break;
780              idx = 0;          }
781              do {          if( c == -1 )
782                  if( (c = asctobin[c]) == 255 )              set_armor_error("premature eof (no CRC)\n");
783                      break;          else {
784                  switch(idx) {              u32 mycrc = 0;
785                  case 0: val =  c << 2; break;              idx = 0;
786                  case 1: val |= (c>>4)&3; mycrc |= val << 16;val=(c<<4)&0xf0;break;              do {
787                  case 2: val |= (c>>2)&15; mycrc |= val << 8;val=(c<<6)&0xc0;break;                  if( (c = asctobin[c]) == 255 )
788                  case 3: val |= c&0x3f; mycrc |= val; break;                      break;
789                  }                  switch(idx) {
790                  for(;;) {                  case 0: val =  c << 2; break;
791                      if( afx->buffer_pos < afx->buffer_len )                  case 1: val |= (c>>4)&3; mycrc |= val << 16;val=(c<<4)&0xf0;break;
792                          c = afx->buffer[afx->buffer_pos++];                  case 2: val |= (c>>2)&15; mycrc |= val << 8;val=(c<<6)&0xc0;break;
793                      else { /* read the next line */                  case 3: val |= c&0x3f; mycrc |= val; break;
794                          unsigned maxlen = MAX_LINELEN;                  }
795                          afx->buffer_pos = 0;                  for(;;) {
796                          afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,                      if( afx->buffer_pos < afx->buffer_len )
797                                                             &afx->buffer_size,                          c = afx->buffer[afx->buffer_pos++];
798                                                             &maxlen );                      else { /* read the next line */
799                          if( !maxlen )                          unsigned maxlen = MAX_LINELEN;
800                              afx->truncated++;                          afx->buffer_pos = 0;
801                          if( !afx->buffer_len )                          afx->buffer_len = gpg_iobuf_read_line( a, &afx->buffer,
802                              break; /* eof */                                                             &afx->buffer_size,
803                          continue;                                                             &maxlen );
804                      }                          if( !maxlen )
805                      break;                              afx->truncated++;
806                  }                          if( !afx->buffer_len )
807                  if( !afx->buffer_len )                              break; /* eof */
808                      break; /* eof */                          continue;
809              } while( ++idx < 4 );                      }
810              if( c == -1 ) {                      break;
811                  set_armor_error("premature eof (in CRC)\n");                  }
812                  rc = invalid_crc();                  if( !afx->buffer_len )
813              }                      break; /* eof */
814              else if( idx != 4 ) {              } while( ++idx < 4 );
815                  set_armor_error("malformed CRC\n");              if( c == -1 ) {
816                  rc = invalid_crc();                  set_armor_error("premature eof (in CRC)\n");
817              }                  rc = invalid_crc();
818              else if( mycrc != afx->crc ) {              }
819                  char msg[128];              else if( idx != 4 ) {
820                  _snprintf( msg, sizeof msg-1,                  set_armor_error("malformed CRC\n");
821                   "CRC error; %06lx - %06lx\n",                  rc = invalid_crc();
822                          (ulong)afx->crc, (ulong)mycrc);              }
823                  set_armor_error( msg );              else if( mycrc != afx->crc ) {
824                  rc = invalid_crc();                  char msg[128];
825              }                  _snprintf( msg, sizeof msg-1,
826              else {                   "CRC error; %06lx - %06lx\n",
827                  rc = 0;                          (ulong)afx->crc, (ulong)mycrc);
828              }                  set_armor_error( msg );
829          }                  rc = invalid_crc();
830      }              }
831                    else {
832      if( !n )                  rc = 0;
833          rc = -1;              }
834                }
835      *retn = n;      }
836      return rc;      
837  }      if( !n )
838            rc = -1;
839  /****************      
840   * This filter is used to handle the armor stuff      *retn = n;
841   */      return rc;
842  int  }
843  gpg_armor_filter( void *opaque, int control,  
844                    gpg_iobuf_t a, byte *buf, size_t *ret_len)  /****************
845  {   * This filter is used to handle the armor stuff
846      size_t size = *ret_len;   */
847      armor_filter_context_t *afx = opaque;  int
848      int rc=0, i, c;  gpg_armor_filter( void *opaque, int control,
849      byte radbuf[3];                    gpg_iobuf_t a, byte *buf, size_t *ret_len)
850      int  idx, idx2;  {
851      size_t n=0;      size_t size = *ret_len;
852      u32 crc;        armor_filter_context_t *afx = opaque;
853            int rc=0, i, c;
854      if( control == IOBUFCTRL_UNDERFLOW && afx->inp_bypass ) {      byte radbuf[3];
855          n = 0;      int  idx, idx2;
856          if( afx->buffer_len ) {      size_t n=0;
857              for(; n < size && afx->buffer_pos < afx->buffer_len; n++ )      u32 crc;  
858                  buf[n++] = afx->buffer[afx->buffer_pos++];      
859              if( afx->buffer_pos >= afx->buffer_len )      if( control == IOBUFCTRL_UNDERFLOW && afx->inp_bypass ) {
860                  afx->buffer_len = 0;          n = 0;
861          }          if( afx->buffer_len ) {
862          for(; n < size; n++ ) {              for(; n < size && afx->buffer_pos < afx->buffer_len; n++ )
863              if( (c=gpg_iobuf_get(a)) == -1 )                  buf[n++] = afx->buffer[afx->buffer_pos++];
864                  break;              if( afx->buffer_pos >= afx->buffer_len )
865              buf[n] = c & 0xff;                  afx->buffer_len = 0;
866          }          }
867          if( !n )          for(; n < size; n++ ) {
868              rc = -1;              if( (c=gpg_iobuf_get(a)) == -1 )
869          *ret_len = n;                  break;
870      }              buf[n] = c & 0xff;
871      else if( control == IOBUFCTRL_UNDERFLOW ) {          }
872          /* We need some space for the faked packet.  The minmum required          if( !n )
873           * size is ~18 + length of the session marker */              rc = -1;
874          if( size < 50 ) {          *ret_len = n;
875              printf( "This is a BUG.\n%s:%d\n", __FILE__, __LINE__ );      }
876              exit( -1 ); /* supplied buffer too short */      else if( control == IOBUFCTRL_UNDERFLOW ) {
877          }          /* We need some space for the faked packet.  The minmum required
878          if( afx->faked )           * size is ~18 + length of the session marker */
879              rc = fake_packet( afx, a, &n, buf, size );          if( size < 50 ) {
880          else if( !afx->inp_checked ) {              printf( "This is a BUG.\n%s:%d\n", __FILE__, __LINE__ );
881              rc = check_input( afx, a );              exit( -1 ); /* supplied buffer too short */
882              if( afx->inp_bypass ) {          }
883                  for(n=0; n < size && afx->buffer_pos < afx->buffer_len; )          if( afx->faked )
884                      buf[n++] = afx->buffer[afx->buffer_pos++];              rc = fake_packet( afx, a, &n, buf, size );
885                  if( afx->buffer_pos >= afx->buffer_len )          else if( !afx->inp_checked ) {
886                      afx->buffer_len = 0;              rc = check_input( afx, a );
887                  if( !n )              if( afx->inp_bypass ) {
888                      rc = -1;                  for(n=0; n < size && afx->buffer_pos < afx->buffer_len; )
889              }                      buf[n++] = afx->buffer[afx->buffer_pos++];
890              else if( afx->faked ) {                  if( afx->buffer_pos >= afx->buffer_len )
891                  unsigned int hashes = afx->hashes;                      afx->buffer_len = 0;
892                  const byte *sesmark;                  if( !n )
893                  size_t sesmarklen;                      rc = -1;
894                                }
895                  sesmark = get_session_marker( &sesmarklen );              else if( afx->faked ) {
896                  if ( sesmarklen > 20 ) {                  unsigned int hashes = afx->hashes;
897                      printf( "This is a BUG.\n%s:%d\n", __FILE__, __LINE__ );                  const byte *sesmark;
898                      exit( -1 );                  size_t sesmarklen;
899                  }                  
900                  /* the buffer is at least 15+n*15 bytes long, so it                  sesmark = get_session_marker( &sesmarklen );
901                   * is easy to construct the packets */                  if ( sesmarklen > 20 ) {
902                                        printf( "This is a BUG.\n%s:%d\n", __FILE__, __LINE__ );
903                  hashes &= 1|2|4|8;                      exit( -1 );
904                  if( !hashes ) {                  }
905                      hashes |= 4;  /* default to MD 5 */                  /* the buffer is at least 15+n*15 bytes long, so it
906                      afx->pgp2mode = 1;                   * is easy to construct the packets */
907                  }                  
908                  n=0;                  hashes &= 1|2|4|8;
909                  /* first a gpg control packet */                  if( !hashes ) {
910                  buf[n++] = 0xff; /* new format, type 63, 1 length byte */                      hashes |= 4;  /* default to MD 5 */
911                  n++;   /* see below */                      afx->pgp2mode = 1;
912                  memcpy(buf+n, sesmark, sesmarklen ); n+= sesmarklen;                  }
913                  buf[n++] = CTRLPKT_CLEARSIGN_START;                  n=0;
914                  buf[n++] = afx->not_dash_escaped? 0:1; /* sigclass */                  /* first a gpg control packet */
915                  if( hashes & 1 )                  buf[n++] = 0xff; /* new format, type 63, 1 length byte */
916                      buf[n++] = DIGEST_ALGO_RMD160;                  n++;   /* see below */
917                  if( hashes & 2 )                  memcpy(buf+n, sesmark, sesmarklen ); n+= sesmarklen;
918                      buf[n++] = DIGEST_ALGO_SHA1;                  buf[n++] = CTRLPKT_CLEARSIGN_START;
919                  if( hashes & 4 )                  buf[n++] = afx->not_dash_escaped? 0:1; /* sigclass */
920                      buf[n++] = DIGEST_ALGO_MD5;                  if( hashes & 1 )
921                  buf[1] = n - 2;                      buf[n++] = DIGEST_ALGO_RMD160;
922                                    if( hashes & 2 )
923                  /* followed by a plaintext packet */                      buf[n++] = DIGEST_ALGO_SHA1;
924                  buf[n++] = 0xaf; /* old packet format, type 11, var length */                  if( hashes & 4 )
925                  buf[n++] = 0;    /* set the length header */                      buf[n++] = DIGEST_ALGO_MD5;
926                  buf[n++] = 6;                  buf[1] = n - 2;
927                  buf[n++] = 't';  /* canonical text mode */                  
928                  buf[n++] = 0;    /* namelength */                  /* followed by a plaintext packet */
929                  memset(buf+n, 0, 4); /* timestamp */                  buf[n++] = 0xaf; /* old packet format, type 11, var length */
930                  n += 4;                  buf[n++] = 0;    /* set the length header */
931              }                  buf[n++] = 6;
932              else if( !rc )                  buf[n++] = 't';  /* canonical text mode */
933                  rc = radix64_read( afx, a, &n, buf, size );                  buf[n++] = 0;    /* namelength */
934          }                  memset(buf+n, 0, 4); /* timestamp */
935          else                  n += 4;
936              rc = radix64_read( afx, a, &n, buf, size );                    }
937          *ret_len = n;              else if( !rc )
938      }                  rc = radix64_read( afx, a, &n, buf, size );
939      else if( control == IOBUFCTRL_FLUSH && !afx->cancel ) {          }
940          /* we don't need this ;-) */          else
941      }              rc = radix64_read( afx, a, &n, buf, size );      
942      else if( control == IOBUFCTRL_INIT ) {          *ret_len = n;
943          if( !is_initialized )      }
944              initialize();      else if( control == IOBUFCTRL_FLUSH && !afx->cancel ) {
945      }          /* we don't need this ;-) */
946      else if( control == IOBUFCTRL_CANCEL ) {      }
947          afx->cancel = 1;      else if( control == IOBUFCTRL_INIT ) {
948      }          if( !is_initialized )
949      else if( control == IOBUFCTRL_FREE ) {              initialize();
950          if( afx->cancel )      }
951              ;      else if( control == IOBUFCTRL_CANCEL ) {
952          else if( afx->status ) { /* pad, write cecksum, and bottom line */          afx->cancel = 1;
953              crc = afx->crc;      }
954              idx = afx->idx;      else if( control == IOBUFCTRL_FREE ) {
955              idx2 = afx->idx2;          if( afx->cancel )
956              for(i=0; i < idx; i++ )              ;
957                  radbuf[i] = afx->radbuf[i];          else if( afx->status ) { /* pad, write cecksum, and bottom line */
958              if( idx ) {              crc = afx->crc;
959                  c = bintoasc[(*radbuf>>2)&077];              idx = afx->idx;
960                  gpg_iobuf_put(a, c);              idx2 = afx->idx2;
961                  if( idx == 1 ) {              for(i=0; i < idx; i++ )
962                      c = bintoasc[((*radbuf << 4) & 060) & 077];                  radbuf[i] = afx->radbuf[i];
963                      gpg_iobuf_put(a, c);              if( idx ) {
964                      gpg_iobuf_put(a, '=');                  c = bintoasc[(*radbuf>>2)&077];
965                      gpg_iobuf_put(a, '=');                  gpg_iobuf_put(a, c);
966                  }                  if( idx == 1 ) {
967                  else { /* 2 */                      c = bintoasc[((*radbuf << 4) & 060) & 077];
968                      c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];                      gpg_iobuf_put(a, c);
969                      gpg_iobuf_put(a, c);                      gpg_iobuf_put(a, '=');
970                      c = bintoasc[((radbuf[1] << 2) & 074) & 077];                      gpg_iobuf_put(a, '=');
971                      gpg_iobuf_put(a, c);                  }
972                      gpg_iobuf_put(a, '=');                  else { /* 2 */
973                  }                      c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
974                  if( ++idx2 >= (64/4) ) { /* pgp doesn't like 72 here */                      gpg_iobuf_put(a, c);
975                      gpg_iobuf_writestr(a, LF );                      c = bintoasc[((radbuf[1] << 2) & 074) & 077];
976                      idx2=0;                      gpg_iobuf_put(a, c);
977                  }                      gpg_iobuf_put(a, '=');
978              }                  }
979              /* may need a linefeed */                  if( ++idx2 >= (64/4) ) { /* pgp doesn't like 72 here */
980              if( idx2 )                      gpg_iobuf_writestr(a, LF );
981                  gpg_iobuf_writestr(a, LF );                      idx2=0;
982              /* write the CRC */                  }
983              gpg_iobuf_put(a, '=');              }
984              radbuf[0] = crc >>16;              /* may need a linefeed */
985              radbuf[1] = crc >> 8;              if( idx2 )
986              radbuf[2] = crc;                  gpg_iobuf_writestr(a, LF );
987              c = bintoasc[(*radbuf >> 2) & 077];              /* write the CRC */
988              gpg_iobuf_put(a, c);              gpg_iobuf_put(a, '=');
989              c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];              radbuf[0] = crc >>16;
990              gpg_iobuf_put(a, c);              radbuf[1] = crc >> 8;
991              c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];              radbuf[2] = crc;
992              gpg_iobuf_put(a, c);              c = bintoasc[(*radbuf >> 2) & 077];
993              c = bintoasc[radbuf[2]&077];              gpg_iobuf_put(a, c);
994              gpg_iobuf_put(a, c);              c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
995              gpg_iobuf_writestr(a, LF );              gpg_iobuf_put(a, c);
996              /* and the the trailer */              c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
997              if( afx->what >= DIM(tail_strings) )              gpg_iobuf_put(a, c);
998                  printf("afx->what=%d", afx->what);              c = bintoasc[radbuf[2]&077];
999              gpg_iobuf_writestr(a, "-----");              gpg_iobuf_put(a, c);
1000              gpg_iobuf_writestr(a, tail_strings[afx->what] );              gpg_iobuf_writestr(a, LF );
1001              gpg_iobuf_writestr(a, "-----" LF );              /* and the the trailer */
1002          }              if( afx->what >= DIM(tail_strings) )
1003          else if( !afx->any_data && !afx->inp_bypass ) {                  printf("afx->what=%d", afx->what);
1004              set_armor_error("no valid OpenPGP data found.\n");              gpg_iobuf_writestr(a, "-----");
1005              afx->no_openpgp_data = 1;              gpg_iobuf_writestr(a, tail_strings[afx->what] );
1006              printf( "[GNUPG:] NODATA 1" );                        gpg_iobuf_writestr(a, "-----" LF );
1007          }          }
1008          if( afx->truncated ) {          else if( !afx->any_data && !afx->inp_bypass ) {
1009              char msg[128];              set_armor_error("no valid OpenPGP data found.\n");
1010              _snprintf( msg, sizeof msg-1, "invalid armor: line longer than %d characters\n",                   MAX_LINELEN );              afx->no_openpgp_data = 1;
1011              set_armor_error( msg );              printf( "[GNUPG:] NODATA 1" );          
1012          }          }
1013          /* issue an error to enforce dissemination of correct software */          if( afx->truncated ) {
1014          if( afx->qp_detected )              char msg[128];
1015              set_armor_error("quoted printable character in armor - "              _snprintf( msg, sizeof msg-1, "invalid armor: line longer than %d characters\n",                   MAX_LINELEN );
1016                       "probably a buggy MTA has been used\n" );              set_armor_error( msg );
1017          safe_free( afx->buffer );          }
1018          afx->buffer = NULL;          /* issue an error to enforce dissemination of correct software */
1019      }          if( afx->qp_detected )
1020      else if( control == IOBUFCTRL_DESC )              set_armor_error("quoted printable character in armor - "
1021          *(char**)buf = "armor_filter";                       "probably a buggy MTA has been used\n" );
1022      return rc;          safe_free( afx->buffer );
1023  }          afx->buffer = NULL;
1024        }
1025  /***********************************************      else if( control == IOBUFCTRL_DESC )
1026   *  For the pipemode command we can't use the armor filter for various          *(char**)buf = "armor_filter";
1027   *  reasons, so we use this new unarmor_pump stuff to remove the armor      return rc;
1028   */  }
1029    
1030  enum unarmor_state_e {  /***********************************************
1031      STA_init = 0,   *  For the pipemode command we can't use the armor filter for various
1032      STA_bypass,   *  reasons, so we use this new unarmor_pump stuff to remove the armor
1033      STA_wait_newline,   */
1034      STA_wait_dash,  
1035      STA_first_dash,  enum unarmor_state_e {
1036      STA_compare_header,      STA_init = 0,
1037      STA_found_header_wait_newline,      STA_bypass,
1038      STA_skip_header_lines,      STA_wait_newline,
1039      STA_skip_header_lines_non_ws,      STA_wait_dash,
1040      STA_read_data,      STA_first_dash,
1041      STA_wait_crc,      STA_compare_header,
1042      STA_read_crc,      STA_found_header_wait_newline,
1043      STA_ready      STA_skip_header_lines,
1044  };      STA_skip_header_lines_non_ws,
1045        STA_read_data,
1046  struct unarmor_pump_s {      STA_wait_crc,
1047      enum unarmor_state_e state;      STA_read_crc,
1048      byte val;      STA_ready
1049      int checkcrc;  };
1050      int pos;   /* counts from 0..3 */  
1051      u32 crc;  struct unarmor_pump_s {
1052      u32 mycrc; /* the one store in the data */      enum unarmor_state_e state;
1053  };      byte val;
1054        int checkcrc;
1055        int pos;   /* counts from 0..3 */
1056        u32 crc;
1057  UnarmorPump      u32 mycrc; /* the one store in the data */
1058  unarmor_pump_new (void)  };
1059  {  
1060      UnarmorPump x;  
1061        
1062      if( !is_initialized )  UnarmorPump
1063          initialize();  unarmor_pump_new (void)
1064      x = calloc (1, sizeof *x);  {
1065      return x;      UnarmorPump x;
1066  }      
1067        if( !is_initialized )
1068  void          initialize();
1069  unarmor_pump_release (UnarmorPump x)      x = calloc (1, sizeof *x);
1070  {      return x;
1071      safe_free (x);  }
1072  }  
1073    void
1074  /*  unarmor_pump_release (UnarmorPump x)
1075   * Get the next character from the ascii armor taken from the gpg_iobuf_t  {
1076   * created earlier by unarmor_pump_new().      safe_free (x);
1077   * Return:  c = Character  }
1078   *        256 = ignore this value  
1079   *         -1 = End of current armor  /*
1080   *         -2 = Premature EOF (not used)   * Get the next character from the ascii armor taken from the gpg_iobuf_t
1081   *         -3 = Invalid armor   * created earlier by unarmor_pump_new().
1082   */   * Return:  c = Character
1083  int   *        256 = ignore this value
1084  unarmor_pump (UnarmorPump x, int c)   *         -1 = End of current armor
1085  {   *         -2 = Premature EOF (not used)
1086      int rval = 256; /* default is to ignore the return value */   *         -3 = Invalid armor
1087         */
1088      switch (x->state) {  int
1089      case STA_init:  unarmor_pump (UnarmorPump x, int c)
1090      {  {
1091          byte tmp[1];      int rval = 256; /* default is to ignore the return value */
1092          tmp[0] = c;      
1093          if ( is_armored (tmp) )      switch (x->state) {
1094              x->state = c == '-'? STA_first_dash : STA_wait_newline;      case STA_init:
1095          else {      {
1096              x->state = STA_bypass;          byte tmp[1];
1097              return c;          tmp[0] = c;
1098          }          if ( is_armored (tmp) )
1099      }              x->state = c == '-'? STA_first_dash : STA_wait_newline;
1100      break;          else {
1101      case STA_bypass:              x->state = STA_bypass;
1102          return c; /* return here to avoid crc calculation */              return c;
1103      case STA_wait_newline:          }
1104          if (c == '\n')      }
1105              x->state = STA_wait_dash;      break;
1106          break;      case STA_bypass:
1107      case STA_wait_dash:          return c; /* return here to avoid crc calculation */
1108          x->state = c == '-'? STA_first_dash : STA_wait_newline;      case STA_wait_newline:
1109          break;          if (c == '\n')
1110      case STA_first_dash: /* just need for initalization */              x->state = STA_wait_dash;
1111          x->pos = 0;          break;
1112          x->state = STA_compare_header;      case STA_wait_dash:
1113      case STA_compare_header:          x->state = c == '-'? STA_first_dash : STA_wait_newline;
1114          if ( "-----BEGIN PGP SIGNATURE-----"[++x->pos] == c ) {          break;
1115              if ( x->pos == 28 )      case STA_first_dash: /* just need for initalization */
1116                  x->state = STA_found_header_wait_newline;          x->pos = 0;
1117          }          x->state = STA_compare_header;
1118          else      case STA_compare_header:
1119              x->state = c == '\n'? STA_wait_dash : STA_wait_newline;          if ( "-----BEGIN PGP SIGNATURE-----"[++x->pos] == c ) {
1120          break;              if ( x->pos == 28 )
1121      case STA_found_header_wait_newline:                  x->state = STA_found_header_wait_newline;
1122          /* to make CR,LF issues easier we simply allow for white space          }
1123             behind the 5 dashes */          else
1124          if ( c == '\n' )              x->state = c == '\n'? STA_wait_dash : STA_wait_newline;
1125              x->state = STA_skip_header_lines;          break;
1126          else if ( c != '\r' && c != ' ' && c != '\t' )      case STA_found_header_wait_newline:
1127              x->state = STA_wait_dash; /* garbage after the header line */          /* to make CR,LF issues easier we simply allow for white space
1128          break;             behind the 5 dashes */
1129      case STA_skip_header_lines:          if ( c == '\n' )
1130          /* i.e. wait for one empty line */              x->state = STA_skip_header_lines;
1131          if ( c == '\n' ) {          else if ( c != '\r' && c != ' ' && c != '\t' )
1132              x->state = STA_read_data;              x->state = STA_wait_dash; /* garbage after the header line */
1133              x->crc = CRCINIT;          break;
1134              x->val = 0;      case STA_skip_header_lines:
1135              x->pos = 0;          /* i.e. wait for one empty line */
1136          }          if ( c == '\n' ) {
1137          else if ( c != '\r' && c != ' ' && c != '\t' )              x->state = STA_read_data;
1138              x->state = STA_skip_header_lines_non_ws;              x->crc = CRCINIT;
1139          break;              x->val = 0;
1140      case STA_skip_header_lines_non_ws:              x->pos = 0;
1141          /* like above but we already encountered non white space */          }
1142          if ( c == '\n' )          else if ( c != '\r' && c != ' ' && c != '\t' )
1143              x->state = STA_skip_header_lines;              x->state = STA_skip_header_lines_non_ws;
1144          break;          break;
1145      case STA_read_data:      case STA_skip_header_lines_non_ws:
1146          /* fixme: we don't check for the trailing dash lines but rely          /* like above but we already encountered non white space */
1147           * on the armor stop characters */          if ( c == '\n' )
1148          if( c == '\n' || c == ' ' || c == '\r' || c == '\t' )              x->state = STA_skip_header_lines;
1149              break; /* skip all kind of white space */          break;
1150                case STA_read_data:
1151          if( c == '=' ) { /* pad character: stop */          /* fixme: we don't check for the trailing dash lines but rely
1152              if( x->pos == 1 ) /* in this case val has some value */           * on the armor stop characters */
1153                  rval = x->val;          if( c == '\n' || c == ' ' || c == '\r' || c == '\t' )
1154              x->state = STA_wait_crc;              break; /* skip all kind of white space */
1155              break;          
1156          }          if( c == '=' ) { /* pad character: stop */
1157                        if( x->pos == 1 ) /* in this case val has some value */
1158          {                  rval = x->val;
1159              int c2;              x->state = STA_wait_crc;
1160              if( (c = asctobin[(c2=c)]) == 255 ) {              break;
1161                  char msg[128];          }
1162                  _snprintf( msg, sizeof msg-1, "invalid radix64 character %02x skipped\n", c2);          
1163                  set_armor_error( msg );          {
1164                  break;              int c2;
1165              }              if( (c = asctobin[(c2=c)]) == 255 ) {
1166          }                  char msg[128];
1167                            _snprintf( msg, sizeof msg-1, "invalid radix64 character %02x skipped\n", c2);
1168          switch(x->pos) {                  set_armor_error( msg );
1169          case 0:                  break;
1170              x->val = c << 2;              }
1171              break;          }
1172          case 1:          
1173              x->val |= (c>>4)&3;          switch(x->pos) {
1174              rval = x->val;          case 0:
1175              x->val = (c<<4)&0xf0;              x->val = c << 2;
1176              break;              break;
1177          case 2:          case 1:
1178              x->val |= (c>>2)&15;              x->val |= (c>>4)&3;
1179              rval = x->val;              rval = x->val;
1180              x->val = (c<<6)&0xc0;              x->val = (c<<4)&0xf0;
1181              break;              break;
1182          case 3:          case 2:
1183              x->val |= c&0x3f;              x->val |= (c>>2)&15;
1184              rval = x->val;              rval = x->val;
1185              break;              x->val = (c<<6)&0xc0;
1186          }              break;
1187          x->pos = (x->pos+1) % 4;          case 3:
1188          break;              x->val |= c&0x3f;
1189      case STA_wait_crc:              rval = x->val;
1190          if( c == '\n' || c == ' ' || c == '\r' || c == '\t' || c == '=' )              break;
1191              break; /* skip ws and pad characters */          }
1192          /* assume that we are at the next line */          x->pos = (x->pos+1) % 4;
1193          x->state = STA_read_crc;          break;
1194          x->pos = 0;      case STA_wait_crc:
1195          x->mycrc = 0;          if( c == '\n' || c == ' ' || c == '\r' || c == '\t' || c == '=' )
1196      case STA_read_crc:              break; /* skip ws and pad characters */
1197          if( (c = asctobin[c]) == 255 ) {          /* assume that we are at the next line */
1198              rval = -1; /* ready */          x->state = STA_read_crc;
1199              if( x->crc != x->mycrc ) {          x->pos = 0;
1200                  char msg[128];          x->mycrc = 0;
1201                  _snprintf( msg, sizeof msg-1, "CRC error; %06lx - %06lx\n",      case STA_read_crc:
1202                          (ulong)x->crc, (ulong)x->mycrc);          if( (c = asctobin[c]) == 255 ) {
1203                  set_armor_error( msg );              rval = -1; /* ready */
1204                  if ( invalid_crc() )              if( x->crc != x->mycrc ) {
1205                      rval = -3;                  char msg[128];
1206              }                  _snprintf( msg, sizeof msg-1, "CRC error; %06lx - %06lx\n",
1207              x->state = STA_ready; /* not sure whether this is correct */                          (ulong)x->crc, (ulong)x->mycrc);
1208              break;                  set_armor_error( msg );
1209          }                  if ( invalid_crc() )
1210                                rval = -3;
1211          switch(x->pos) {              }
1212          case 0:              x->state = STA_ready; /* not sure whether this is correct */
1213              x->val = c << 2;              break;
1214              break;          }
1215          case 1:          
1216              x->val |= (c>>4)&3;          switch(x->pos) {
1217              x->mycrc |= x->val << 16;          case 0:
1218              x->val = (c<<4)&0xf0;              x->val = c << 2;
1219              break;              break;
1220          case 2:          case 1:
1221              x->val |= (c>>2)&15;              x->val |= (c>>4)&3;
1222              x->mycrc |= x->val << 8;              x->mycrc |= x->val << 16;
1223              x->val = (c<<6)&0xc0;              x->val = (c<<4)&0xf0;
1224              break;              break;
1225          case 3:          case 2:
1226              x->val |= c&0x3f;              x->val |= (c>>2)&15;
1227              x->mycrc |= x->val;              x->mycrc |= x->val << 8;
1228              break;              x->val = (c<<6)&0xc0;
1229          }              break;
1230          x->pos = (x->pos+1) % 4;          case 3:
1231          break;              x->val |= c&0x3f;
1232      case STA_ready:              x->mycrc |= x->val;
1233          rval = -1;              break;
1234          break;          }
1235      }          x->pos = (x->pos+1) % 4;
1236                break;
1237      if ( !(rval & ~255) ) { /* compute the CRC */      case STA_ready:
1238          x->crc = (x->crc << 8) ^ crc_table[((x->crc >> 16)&0xff) ^ rval];          rval = -1;
1239          x->crc &= 0x00ffffff;          break;
1240      }      }
1241            
1242      return rval;      if ( !(rval & ~255) ) { /* compute the CRC */
1243  }          x->crc = (x->crc << 8) ^ crc_table[((x->crc >> 16)&0xff) ^ rval];
1244            x->crc &= 0x00ffffff;
1245        }
1246        
1247        return rval;
1248    }
1249    
1250    

Legend:
Removed from v.2  
changed lines
  Added in v.46

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26