See ChangeLog: Fri Nov 27 15:30:24 CET 1998 Werner Koch
[gnupg.git] / g10 / armor.c
index 45f962f..78656ba 100644 (file)
@@ -1,14 +1,14 @@
-/* armor.c - Armor filter
+/* armor.c - Armor flter
  *     Copyright (C) 1998 Free Software Foundation, Inc.
  *
- * This file is part of GNUPG.
+ * This file is part of GnuPG.
  *
- * GNUPG is free software; you can redistribute it and/or modify
+ * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * GNUPG is distributed in the hope that it will be useful,
+ * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
@@ -34,6 +34,7 @@
 #include "options.h"
 #include "main.h"
 #include "status.h"
+#include "i18n.h"
 
 
 #define CRCINIT 0xB704CE
@@ -51,7 +52,7 @@ static int is_initialized;
 
 
 typedef enum {
-    fhdrHASArmor,
+    fhdrHASArmor = 0,
     fhdrNOArmor,
     fhdrINIT,
     fhdrINITCont,
@@ -73,7 +74,10 @@ typedef enum {
     fhdrENDClearsig,
     fhdrENDClearsigHelp,
     fhdrTESTSpaces,
+    fhdrCLEARSIGSimple,
+    fhdrCLEARSIGSimpleNext,
     fhdrTEXT,
+    fhdrTEXTSimple,
     fhdrERROR,
     fhdrERRORShow,
     fhdrEOF
@@ -108,7 +112,8 @@ static char *tail_strings[] = {
 static fhdr_state_t find_header( fhdr_state_t state,
                                 byte *buf, size_t *r_buflen,
                                 IOBUF a, size_t n,
-                                unsigned *r_empty, int *r_hashes );
+                                unsigned *r_empty, int *r_hashes,
+                                int only_keyblocks, int *not_dashed );
 
 
 static void
@@ -158,11 +163,13 @@ is_armored( byte *buf )
     pkttype =  ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf);
     switch( pkttype ) {
       case PKT_MARKER:
+      case PKT_SYMKEY_ENC:
       case PKT_PUBLIC_KEY:
       case PKT_SECRET_KEY:
       case PKT_PUBKEY_ENC:
       case PKT_SIGNATURE:
       case PKT_COMMENT:
+      case PKT_OLD_COMMENT:
       case PKT_PLAINTEXT:
       case PKT_COMPRESSED:
       case PKT_ENCRYPTED:
@@ -257,7 +264,8 @@ parse_hash_header( const char *line )
  */
 static fhdr_state_t
 find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
-            IOBUF a, size_t n, unsigned *r_empty, int *r_hashes )
+            IOBUF a, size_t n, unsigned *r_empty, int *r_hashes,
+            int only_keyblocks, int *not_dashed )
 {
     int c=0, i;
     const char *s;
@@ -270,7 +278,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
 
     buflen = *r_buflen;
     assert(buflen >= 100 );
-    buflen -= 3; /* reserved room for CR,LF and one extra */
+    buflen -= 4; /* reserved room for CR,LF, and two extra */
 
     do {
        switch( state ) {
@@ -278,14 +286,17 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
            /* read at least the first byte to check whether it is armored
             * or not */
            c = 0;
-           for(n=0; n < 28 && (c=iobuf_get2(a)) != -1 && c != '\n'; )
+           for(n=0; n < 28 && (c=iobuf_get(a)) != -1 && c != '\n'; )
                buf[n++] = c;
            if( !n && c == '\n' )
                state = fhdrCHECKBegin;
            else if( !n  || c == -1 )
                state = fhdrNOArmor; /* too short */
-           else if( !is_armored( buf ) )
+           else if( !is_armored( buf ) ) {
                state = fhdrNOArmor;
+               if( c == '\n' )
+                   buf[n++] = c;
+           }
            else if( c == '\n' )
                state = fhdrCHECKBegin;
            else
@@ -296,7 +307,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
            n = 0;
          case fhdrINITCont: /* read more stuff into buffer */
            c = 0;
-           for(; n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n'; )
+           for(; n < buflen && (c=iobuf_get(a)) != -1 && c != '\n'; )
                buf[n++] = c;
            state = c == '\n' ? fhdrCHECKBegin :
                     c == -1  ? fhdrEOF : fhdrINITSkip;
@@ -306,21 +317,21 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
            if( c == '\n' )
                n = 0;
            else {
-               while( (c=iobuf_get2(a)) != -1 && c != '\n' )
+               while( (c=iobuf_get(a)) != -1 && c != '\n' )
                    ;
            }
            state =  c == -1? fhdrEOF : fhdrINIT;
            break;
 
          case fhdrSKIPHeader:
-           while( (c=iobuf_get2(a)) != -1 && c != '\n' )
+           while( (c=iobuf_get(a)) != -1 && c != '\n' )
                ;
            state =  c == -1? fhdrEOF : fhdrWAITHeader;
            break;
 
          case fhdrWAITHeader: /* wait for Header lines */
            c = 0;
-           for(n=0; n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n'; )
+           for(n=0; n < buflen && (c=iobuf_get(a)) != -1 && c != '\n'; )
                buf[n++] = c;
            buf[n] = 0;
            if( n < buflen || c == '\n' ) {
@@ -330,13 +341,20 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
                        if( buf[n-1] == '\r' )
                            buf[--n] = 0;
                        if( opt.verbose ) {
-                           log_info("armor header: ");
+                           log_info(_("armor header: "));
                            print_string( stderr, buf, n, 0 );
                            putc('\n', stderr);
                        }
                        if( clearsig && !(hashes=parse_hash_header( buf )) ) {
-                           log_error("invalid clearsig header\n");
-                           state = fhdrERROR;
+                           if( strlen(buf) > 15
+                               && !memcmp( buf, "NotDashEscaped:", 15 ) ) {
+                               *not_dashed = 1;
+                               state = fhdrWAITHeader;
+                           }
+                           else {
+                               log_error(_("invalid clearsig header\n"));
+                               state = fhdrERROR;
+                           }
                        }
                        else {
                            state = fhdrWAITHeader;
@@ -361,7 +379,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
                    }
                }
                else {
-                   log_error("invalid armor header: ");
+                   log_error(_("invalid armor header: "));
                    print_string( stderr, buf, n, 0 );
                    putc('\n', stderr);
                    state = fhdrERROR;
@@ -370,7 +388,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
            else if( c != -1 ) {
                if( strchr( buf, ':') ) { /* buffer to short, but this is okay*/
                    if( opt.verbose ) {
-                       log_info("armor header: ");
+                       log_info(_("armor header: "));
                        print_string( stderr, buf, n, 0 );
                        fputs("[...]\n", stderr);  /* indicate it is truncated */
                    }
@@ -385,12 +403,13 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
 
          case fhdrWAITClearsig: /* skip the empty line (for clearsig) */
            c = 0;
-           for(n=0; n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n'; )
+           for(n=0; n < buflen && (c=iobuf_get(a)) != -1 && c != '\n'; )
                buf[n++] = c;
-           if( n < buflen || c == '\n' ) {
-               buf[n] = 0;
+           if( c != -1 ) {
                if( n > 15 && !memcmp(buf, "-----", 5 ) )
                    state = fhdrNullClearsig;
+               else if( c != '\n' )
+                   state = fhdrREADClearsigNext;
                else
                    state = fhdrCHECKDashEscaped3;
            }
@@ -429,13 +448,41 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
                    break;
            if( !s )
                break; /* unknown begin line */
+           if( only_keyblocks && i != 1 && i != 5 && i != 6 )
+               break; /* not a keyblock armor */
+
            /* found the begin line */
            hdr_line = i;
            state = fhdrWAITHeader;
            if( hdr_line == BEGIN_SIGNED_MSG_IDX )
                clearsig = 1;
            if( opt.verbose > 1 )
-               log_info("armor: %s\n", head_strings[hdr_line]);
+               log_info(_("armor: %s\n"), head_strings[hdr_line]);
+           break;
+
+         case fhdrCLEARSIGSimple:
+           /* we are at the begin of a new line */
+         case fhdrCLEARSIGSimpleNext:
+           n = 0;
+           c = 0;
+           while( n < buflen && (c=iobuf_get(a)) != -1 ) {
+               buf[n++] = c;
+               if( c == '\n' )
+                   break;
+           }
+           buf[n] = 0;
+           if( c == -1 )
+               state = fhdrEOF;
+           else if( state == fhdrCLEARSIGSimple
+                    && n > 15 && !memcmp(buf, "-----", 5 ) ) {
+               if( c == '\n' )
+                   buf[n-1] = 0;
+               state = fhdrENDClearsig;
+           }
+           else if( c == '\n' )
+               state = fhdrCLEARSIGSimple;
+           else
+               state = fhdrCLEARSIGSimpleNext;
            break;
 
          case fhdrCLEARSIG:
@@ -445,7 +492,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
             * we have to look for a header line or dashed escaped text*/
            n = 0;
            c = 0;
-           while( n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n' )
+           while( n < buflen && (c=iobuf_get(a)) != -1 && c != '\n' )
                buf[n++] = c;
            buf[n] = 0;
            if( c == -1 )
@@ -461,6 +508,10 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
            break;
 
          case fhdrCHECKDashEscaped3:
+           if( *not_dashed ) {
+               state = fhdrTEXTSimple;
+               break;
+           }
            if( !(n > 1 && buf[0] == '-' && buf[1] == ' ' ) ) {
                state = fhdrTEXT;
                break;
@@ -479,7 +530,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
                                 fhdrREADClearsig : fhdrTESTSpaces;
            }
            else {
-               log_error("invalid dash escaped line: ");
+               log_error(_("invalid dash escaped line: "));
                print_string( stderr, buf, n, 0 );
                putc('\n', stderr);
                state = fhdrERROR;
@@ -490,7 +541,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
            /* check the clearsig line */
            if( n > 15 && !memcmp(buf, "-----", 5 ) )
                state = fhdrENDClearsig;
-           else if( buf[0] == '-' && buf[1] == ' ' )
+           else if( buf[0] == '-' && buf[1] == ' ' && !*not_dashed )
                state = fhdrCHECKDashEscaped;
            else {
                state = fhdrTESTSpaces;
@@ -501,7 +552,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
            /* check the clearsig line */
            if( n > 15 && !memcmp(buf, "-----", 5 ) )
                state = fhdrENDClearsig;
-           else if( buf[0] == '-' && buf[1] == ' ' )
+           else if( buf[0] == '-' && buf[1] == ' ' && !*not_dashed )
                state = fhdrCHECKDashEscaped2;
            else {
                state = fhdrREADClearsig;
@@ -513,7 +564,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
             * for dashed escaped text of headers */
            c = 0;
            n = 0;
-           while( n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n' )
+           while( n < buflen && (c=iobuf_get(a)) != -1 && c != '\n' )
                buf[n++] = c;
            buf[n] = 0;
            if( c == -1 )
@@ -531,7 +582,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
             * counting spaces is not enough, because it may be a
             * mix of different white space characters */
            IOBUF b = iobuf_temp();
-           while( (c=iobuf_get2(a)) != -1 && c != '\n' ) {
+           while( (c=iobuf_get(a)) != -1 && c != '\n' ) {
                iobuf_put(b,c);
                if( c != ' ' && c != '\t' && c != '\r' )
                    break;
@@ -548,7 +599,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
          } break;
 
          case fhdrERRORShow:
-           log_error("invalid clear text header: ");
+           log_error(_("invalid clear text header: "));
            print_string( stderr, buf, n, 0 );
            putc('\n', stderr);
            state = fhdrERROR;
@@ -580,6 +631,11 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
 
     if( clearsig && state == fhdrTEXT )
        state = fhdrCLEARSIG;
+    else if( clearsig && state == fhdrTEXTSimple ) {
+       state = fhdrCLEARSIGSimple;
+       buf[n] = '\n';
+       n++;
+    }
 
     if( state == fhdrCLEARSIG || state == fhdrREADClearsig ) {
        /* append CR,LF after removing trailing wspaces */
@@ -619,7 +675,8 @@ check_input( armor_filter_context_t *afx, IOBUF a )
 
     n = DIM(afx->helpbuf);
     state = find_header( state, afx->helpbuf, &n, a,
-                               afx->helplen, &emplines, &afx->hashes);
+                               afx->helplen, &emplines, &afx->hashes,
+                               afx->only_keyblocks, &afx->not_dash_escaped );
     switch( state ) {
       case fhdrNOArmor:
        afx->inp_checked = 1;
@@ -637,6 +694,9 @@ check_input( armor_filter_context_t *afx, IOBUF a )
 
       case fhdrNullClearsig:
       case fhdrCLEARSIG: /* start fake package mode (for clear signatures) */
+      case fhdrREADClearsigNext:
+      case fhdrCLEARSIGSimple:
+      case fhdrCLEARSIGSimpleNext:
        afx->helplen = n;
        afx->helpidx = 0;
        afx->faked = 1;
@@ -705,7 +765,9 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
        afx->helpidx = 0;
        state = find_header( state, afx->helpbuf, &n, a,
                              state == fhdrNullClearsig? afx->helplen:0,
-                                               &emplines, &afx->hashes );
+                                               &emplines, &afx->hashes,
+                                               afx->only_keyblocks,
+                                               &afx->not_dash_escaped );
        switch( state) {
          case fhdrERROR:
            invalid_armor();
@@ -720,6 +782,8 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
 
          case fhdrREADClearsig:
          case fhdrREADClearsigNext:
+         case fhdrCLEARSIGSimple:
+         case fhdrCLEARSIGSimpleNext:
            afx->helplen = n;
            break;
 
@@ -778,7 +842,7 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
            break;
        }
        else if( (c = asctobin[(c2=c)]) == 255 ) {
-           log_error("invalid radix64 character %02x skipped\n", c2);
+           log_error(_("invalid radix64 character %02x skipped\n"), c2);
            continue;
        }
        switch(idx) {
@@ -796,7 +860,10 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
     afx->idx = idx;
     afx->radbuf[0] = val;
     if( checkcrc ) {
-       afx->inp_eof = 1; /*assume eof */
+       afx->any_data = 1;
+       afx->inp_checked=0;
+       afx->faked = 0;
+       afx->parse_state = 0;
        for(;;) { /* skip lf and pad characters */
            if( afx->helpidx < afx->helplen )
                c = afx->helpbuf[afx->helpidx++];
@@ -808,7 +875,7 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
            break;
        }
        if( c == -1 )
-           log_error("premature eof (no CRC)\n");
+           log_error(_("premature eof (no CRC)\n"));
        else {
            u32 mycrc = 0;
            idx = 0;
@@ -827,15 +894,15 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
                    break;
            } while( ++idx < 4 );
            if( c == -1 ) {
-               log_error("premature eof (in CRC)\n");
+               log_error(_("premature eof (in CRC)\n"));
                rc = G10ERR_INVALID_ARMOR;
            }
            else if( idx != 4 ) {
-               log_error("malformed CRC\n");
+               log_error(_("malformed CRC\n"));
                rc = G10ERR_INVALID_ARMOR;
            }
            else if( mycrc != afx->crc ) {
-               log_error("CRC error; %06lx - %06lx\n",
+               log_error(_("CRC error; %06lx - %06lx\n"),
                                    (ulong)afx->crc, (ulong)mycrc);
                rc = G10ERR_INVALID_ARMOR;
            }
@@ -854,11 +921,11 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
                if( rc == -1 )
                    rc = 0;
                else if( rc == 2 ) {
-                   log_error("premature eof (in Trailer)\n");
+                   log_error(_("premature eof (in Trailer)\n"));
                    rc = G10ERR_INVALID_ARMOR;
                }
                else {
-                   log_error("error in trailer line\n");
+                   log_error(_("error in trailer line\n"));
                    rc = G10ERR_INVALID_ARMOR;
                }
              #endif
@@ -873,7 +940,6 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
     return rc;
 }
 
-
 /****************
  * This filter is used to handle the armor stuff
  */
@@ -913,13 +979,6 @@ armor_filter( void *opaque, int control,
        if( size < 15+(4*15) )  /* need space for up to 4 onepass_sigs */
            BUG(); /* supplied buffer too short */
 
-       if( afx->inp_eof ) {
-           *ret_len = 0;
-           if( DBG_FILTER )
-               log_debug("armor-filter: eof due to inp_eof flag\n" );
-           return -1;
-       }
-
        if( afx->faked )
            rc = fake_packet( afx, a, &n, buf, size );
        else if( !afx->inp_checked ) {
@@ -1000,10 +1059,27 @@ armor_filter( void *opaque, int control,
            iobuf_writestr(a, "-----");
            iobuf_writestr(a, head_strings[afx->what] );
            iobuf_writestr(a, "-----\n");
-           iobuf_writestr(a, "Version: GNUPG v"  VERSION " ("
+           iobuf_writestr(a, "Version: GnuPG v"  VERSION " ("
                                            PRINTABLE_OS_NAME ")\n");
-           iobuf_writestr(a,
-               "Comment: Get GNUPG from ftp://ftp.guug.de/pub/gcrypt/\n");
+
+           if( opt.comment_string ) {
+               const char *s = opt.comment_string;
+               iobuf_writestr(a, "Comment: " );
+               for( ; *s; s++ ) {
+                   if( *s == '\n' )
+                       iobuf_writestr(a, "\\n" );
+                   else if( *s == '\r' )
+                       iobuf_writestr(a, "\\r" );
+                   else if( *s == '\v' )
+                       iobuf_writestr(a, "\\v" );
+                   else
+                       iobuf_put(a, *s );
+               }
+               iobuf_put(a, '\n' );
+           }
+           else
+               iobuf_writestr(a,
+                   "Comment: For info finger gcrypt@ftp.guug.de\n");
            if( afx->hdrlines )
                iobuf_writestr(a, afx->hdrlines);
            iobuf_put(a, '\n');
@@ -1034,7 +1110,7 @@ armor_filter( void *opaque, int control,
                iobuf_put(a, c);
                c = bintoasc[radbuf[2]&077];
                iobuf_put(a, c);
-               if( ++idx2 >= (72/4) ) {
+               if( ++idx2 >= (64/4) ) { /* pgp doesn't like 72 here */
                    iobuf_put(a, '\n');
                    idx2=0;
                }
@@ -1073,7 +1149,7 @@ armor_filter( void *opaque, int control,
                    iobuf_put(a, c);
                    iobuf_put(a, '=');
                }
-               if( ++idx2 >= (72/4) ) {
+               if( ++idx2 >= (64/4) ) { /* pgp doesn't like 72 here */
                    iobuf_put(a, '\n');
                    idx2=0;
                }
@@ -1102,6 +1178,8 @@ armor_filter( void *opaque, int control,
            iobuf_writestr(a, tail_strings[afx->what] );
            iobuf_writestr(a, "-----\n");
        }
+       else if( !afx->any_data && !afx->inp_bypass )
+           log_error(_("no valid RFC1991 or OpenPGP data found.\n"));
     }
     else if( control == IOBUFCTRL_DESC )
        *(char**)buf = "armor_filter";