armor rewritten, but still buggy
authorWerner Koch <wk@gnupg.org>
Wed, 4 Feb 1998 18:54:31 +0000 (18:54 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 4 Feb 1998 18:54:31 +0000 (18:54 +0000)
16 files changed:
NEWS
TODO
acconfig.h
config.h.in
g10/armor.c
g10/filter.h
g10/g10.c
g10/main.h
g10/mainproc.c
g10/parse-packet.c
g10/sign.c
g10/status.c
g10/status.h
g10/textfilter.c
include/iobuf.h
util/iobuf.c

diff --git a/NEWS b/NEWS
index 41d9b4f..253e8a8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,13 @@
 
-    * added option "--status-fd": see g10/OPTIONS
+    * It's now 64 bit clean and runs fine on an alpha--linux.
+
+    * Key generation is much faster now.  I fixed this by using not
+      so strong random number for the primes (this was a bug because the
+      ElGamal primes are public parameters and it does not make sense
+      to generate them from strong random).  The real secret is the x value
+      which is still generated from strong (okay: /dev/random) random bits.
 
+    * added option "--status-fd": see g10/OPTIONS
 
     * We have secure memeory on systems which support mlock().
       It is not complete yet, because we do not have signal handler
diff --git a/TODO b/TODO
index 18f0314..5a8fc79 100644 (file)
--- a/TODO
+++ b/TODO
@@ -27,3 +27,7 @@
       we have a self-signature -> put this stuff into a kind of directory
       record, as it does not belong to the pubkey record?
 
+    * Have no prototype for stpcpy() when using glibc 2; must switch on
+      the GNU extensions or see how configure can fix it.
+
+
index 728d4d1..f8ddcd5 100644 (file)
 #ifndef G10_CONFIG_H
 #define G10_CONFIG_H
 
+/* need this, because some autoconf tests rely on this (e.g. stpcpy)
+ * and it should be used for new programs
+ */
+#define _GNU_SOURCE  1
 
 @TOP@
 
index 723e53f..31e7990 100644 (file)
 #ifndef G10_CONFIG_H
 #define G10_CONFIG_H
 
+/* need this, because some autoconf tests rely on this (e.g. stpcpy)
+ * and it should be used for new programs
+ */
+#define _GNU_SOURCE  1
 
 
 /* Define to empty if the keyword does not work.  */
index 7269b32..dbe3406 100644 (file)
@@ -32,6 +32,8 @@
 #include "filter.h"
 #include "packet.h"
 #include "options.h"
+#include "main.h"
+#include "status.h"
 
 
 
@@ -65,8 +67,12 @@ typedef enum {
     fhdrEMPTYClearsig,
     fhdrCHECKClearsig,
     fhdrCHECKClearsig2,
+    fhdrCHECKDashEscaped,
+    fhdrCHECKDashEscaped2,
+    fhdrCHECKDashEscaped3,
     fhdrREADClearsigNext,
     fhdrENDClearsig,
+    fhdrTESTSpaces,
     fhdrTEXT,
     fhdrERROR,
     fhdrERRORShow,
@@ -92,8 +98,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);
+static fhdr_state_t find_header( fhdr_state_t state, byte *buf,
+                    size_t *r_buflen, IOBUF a, size_t n, unsigned *r_empty);
 
 
 static void
@@ -156,26 +162,36 @@ is_armored( byte *buf )
     return 1;
 }
 
+static void
+invalid_armor(void)
+{
+    write_status(STATUS_BADARMOR);
+    g10_exit(1); /* stop here */
+}
+
 
 /****************
  * parse an ascii armor.
  * Returns: the state,
  *         the remaining bytes in BUF are returned in RBUFLEN.
+ *         r_empty return the # of empty lines before the buffer
  */
 static fhdr_state_t
-find_header( fhdr_state_t state, byte *buf, size_t *r_buflen, IOBUF a, size_t n)
+find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
+                                       IOBUF a, size_t n, unsigned *r_empty)
 {
     int c, i;
     const char *s;
-    char *p;
+    byte *p;
     size_t buflen;
     int cont;
     int clearsig=0;
     int hdr_line=0;
+    unsigned empty = 0;
 
     buflen = *r_buflen;
     assert(buflen >= 100 );
-    buflen--;
+    buflen -= 3; /* reserved room for CR,LF and one extra */
 
     do {
        switch( state ) {
@@ -183,7 +199,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen, IOBUF a, size_t n)
            /* read 28 bytes, which is the bare minimum for a BEGIN...
             * and check wether this has a Armor. */
            c = 0;
-           for(n=0; n < 28 && (c=iobuf_get(a)) != -1 && c != '\n'; )
+           for(n=0; n < 28 && (c=iobuf_get2(a)) != -1 && c != '\n'; )
                buf[n++] = c;
            if( n < 28 || c == -1 )
                state = fhdrNOArmor; /* too short */
@@ -197,27 +213,27 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen, IOBUF a, size_t n)
            n = 0;
          case fhdrINITCont: /* read more stuff into buffer */
            c = 0;
-           for(; n < buflen && (c=iobuf_get(a)) != -1 && c != '\n'; )
+           for(; n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n'; )
                buf[n++] = c;
            state = c == '\n' ? fhdrCHECKBegin :
                     c == -1  ? fhdrEOF : fhdrINITSkip;
            break;
 
          case fhdrINITSkip:
-           while( (c=iobuf_get(a)) != -1 && c != '\n' )
+           while( (c=iobuf_get2(a)) != -1 && c != '\n' )
                ;
            state =  c == -1? fhdrEOF : fhdrINIT;
            break;
 
          case fhdrSKIPHeader:
-           while( (c=iobuf_get(a)) != -1 && c != '\n' )
+           while( (c=iobuf_get2(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_get(a)) != -1 && c != '\n'; )
+           for(n=0; n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n'; )
                buf[n++] = c;
            buf[n] = 0;
            if( n < buflen || c == '\n' ) {
@@ -229,21 +245,21 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen, IOBUF a, size_t n)
                        state = fhdrWAITHeader;
                    }
                    else
-                       state = fhdrTEXT;
+                       state = fhdrCHECKDashEscaped3;
                }
                else if( !n || (buf[0] == '\r' && !buf[1]) ) { /* empty line */
                    if( clearsig )
                        state = fhdrWAITClearsig;
                    else {
                        /* this is not really correct: if we do not have
-                        * a clearsig and not armor lines we are not allowed
+                        * a clearsig and no armor lines we are not allowed
                         * to have an empty line */
                        n = 0;
                        state = fhdrTEXT;
                    }
                }
                else {
-                   log_debug("invalid armor header: ");
+                   log_error("invalid armor header: ");
                    print_string( stderr, buf, n );
                    putc('\n', stderr);
                    state = fhdrERROR;
@@ -265,17 +281,21 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen, IOBUF a, size_t n)
 
          case fhdrWAITClearsig: /* skip all empty lines (for clearsig) */
            c = 0;
-           for(n=0; n < buflen && (c=iobuf_get(a)) != -1 && c != '\n'; )
+           for(n=0; n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n'; )
                buf[n++] = c;
            if( n < buflen || c == '\n' ) {
                buf[n] = 0;
                if( !n || (buf[0]=='\r' && !buf[1]) ) /* empty line */
                    ;
                else
-                   state = fhdrTEXT;
+                   state = fhdrCHECKDashEscaped3;
            }
-           else
+           else {
+               /* fixme: we should check wether this linee continues
+                *   it is poosible that we have only read ws until here
+                *   and more stuff is to come */
                state = fhdrEOF;
+           }
            break;
 
          case fhdrENDClearsig:
@@ -313,17 +333,17 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen, IOBUF a, size_t n)
          case fhdrEMPTYClearsig:
          case fhdrREADClearsig:
            /* we are at the start of a line: read a clearsig into the buffer
-            * we have to look for a the header line or dashd escaped text*/
+            * we have to look for a the header line or dashed escaped text*/
            n = 0;
            c = 0;
-           for(; n < buflen && (c=iobuf_get(a)) != -1 && c != '\n'; )
+           while( n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n' )
                buf[n++] = c;
            buf[n] = 0;
            if( c == -1 )
                state = fhdrEOF;
            else if( !n || ( buf[0]=='\r' && !buf[1] ) ) {
                state = fhdrEMPTYClearsig;
-               /* FIXME: handle it */
+               empty++;
            }
            else if( c == '\n' )
                state = fhdrCHECKClearsig2;
@@ -331,43 +351,86 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen, IOBUF a, size_t n)
                state = fhdrCHECKClearsig;
            break;
 
+         case fhdrCHECKDashEscaped3:
+           if( !(n > 1 && buf[0] == '-' && buf[1] == ' ' ) ) {
+               state = fhdrTEXT;
+               break;
+           }
+           /* fall through */
+         case fhdrCHECKDashEscaped2:
+         case fhdrCHECKDashEscaped:
+           /* check dash escaped line */
+           if( buf[2] == '-' || ( n > 6 && !memcmp(buf+2, "From ", 5))) {
+               for(i=2; i < n; i++ )
+                   buf[i-2] = buf[i];
+               n -= 2;
+               buf[n] = 0; /* not really needed */
+               state = state == fhdrCHECKDashEscaped3 ? fhdrTEXT :
+                       state == fhdrCHECKDashEscaped2 ?
+                                fhdrREADClearsig : fhdrTESTSpaces;
+           }
+           else {
+               log_error("invalid dash escaped line: ");
+               print_string( stderr, buf, n );
+               putc('\n', stderr);
+               state = fhdrERROR;
+           }
+           break;
+
          case fhdrCHECKClearsig:
          case fhdrCHECKClearsig2:
            /* check the clearsig line */
            if( n > 15 && !memcmp(buf, "-----", 5 ) )
                state = fhdrENDClearsig;
-           else if( buf[0] == '-' && buf[1] == ' ' ) {
-               /* dash escaped line */
-               if( buf[2] == '-' || ( n > 6 && !memcmp(buf+2, "From ", 5))) {
-                   for(i=2; i < n; i++ )
-                       buf[i-2] = buf[i];
-                   n -= 2;
-                   buf[n] = 0; /* not really needed */
-                   state = state == fhdrCHECKClearsig2 ?
-                                    fhdrREADClearsig : fhdrREADClearsigNext;
-                   /* FIXME: add the lf to the buffer */
-               }
-               else {
-                   log_debug("invalid dash escaped line: ");
-                   print_string( stderr, buf, n );
-                   putc('\n', stderr);
-                   state = fhdrERROR;
-               }
-           }
+           else if( buf[0] == '-' && buf[1] == ' ' )
+               state = fhdrCHECKDashEscaped;
            else {
                state = state == fhdrCHECKClearsig2 ?
-                                 fhdrREADClearsig : fhdrREADClearsigNext;
-               /* FIXME: add the lf to the buffer */
+                                 fhdrREADClearsig : fhdrTESTSpaces;
            }
            break;
 
          case fhdrREADClearsigNext:
            /* Read to the end of the line, do not care about checking
             * for dashed escaped text of headers */
+           c = 0;
+           n = 0;
+           while( n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n' )
+               buf[n++] = c;
+           buf[n] = 0;
+           if( c == -1 )
+               state = fhdrEOF;
+           else if( c == '\n' )
+               state = fhdrREADClearsig;
+           else
+               state = fhdrTESTSpaces;
            break;
 
+         case fhdrTESTSpaces: {
+           /* but must check wether the rest of the line
+            * does only contain white spaces; this is problematic
+            * since we may have to restore the stuffs. simply
+            * counting spaces is not enough, because it may be a
+            * mix of different white space chacters */
+           IOBUF b = iobuf_temp();
+           while( (c=iobuf_get2(a)) != -1 && c != '\n' ) {
+               iobuf_put(b,c);
+               if( c != ' ' && c != '\t' && c != '\r' )
+                   break;
+           }
+           if( c == '\n' ) {
+               /* okay we can skip the rest of the line */
+               iobuf_close(b);
+               state = fhdrREADClearsig;
+           }
+           else {
+               iobuf_unget_and_close_temp(a,b);
+               state = fhdrREADClearsigNext;
+           }
+         } break;
+
          case fhdrERRORShow:
-           log_debug("invalid clear text header: ");
+           log_error("invalid clear text header: ");
            print_string( stderr, buf, n );
            putc('\n', stderr);
            state = fhdrERROR;
@@ -386,6 +449,10 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen, IOBUF a, size_t n)
          case fhdrEMPTYClearsig:
          case fhdrCHECKClearsig:
          case fhdrCHECKClearsig2:
+         case fhdrCHECKDashEscaped:
+         case fhdrCHECKDashEscaped2:
+         case fhdrCHECKDashEscaped3:
+         case fhdrTESTSpaces:
          case fhdrERRORShow:
            cont = 1;
            break;
@@ -395,7 +462,28 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen, IOBUF a, size_t n)
 
     if( clearsig && state == fhdrTEXT )
        state = fhdrCLEARSIG;
+
+    if( state == fhdrCLEARSIG || state == fhdrREADClearsig ) {
+       /* append CR,LF after removing trailing wspaces */
+       for(p=buf+n-1; n; n--, p-- ) {
+           assert( *p != '\n' );
+           if( *p != ' ' && *p != '\t' && *p != '\r' ) {
+               p[1] = '\r';
+               p[2] = '\n';
+               n += 2;
+               break;
+           }
+       }
+       if( !n ) {
+           buf[0] = '\r';
+           buf[1] = '\n';
+           n = 2;
+       }
+    }
+
+
     *r_buflen = n;
+    *r_empty = empty;
     return state;
 }
 
@@ -407,12 +495,13 @@ check_input( armor_filter_context_t *afx, IOBUF a )
     int rc = 0;
     size_t n;
     fhdr_state_t state = afx->parse_state;
+    unsigned emplines;
 
     if( state != fhdrENDClearsig )
        state = fhdrHASArmor;
 
     n = DIM(afx->helpbuf);
-    state = find_header( state, afx->helpbuf, &n, a, afx->helplen );
+    state = find_header( state, afx->helpbuf, &n, a, afx->helplen, &emplines);
     switch( state ) {
       case fhdrNOArmor:
        afx->inp_checked = 1;
@@ -421,6 +510,9 @@ check_input( armor_filter_context_t *afx, IOBUF a )
        break;
 
       case fhdrERROR:
+       invalid_armor();
+       break;
+
       case fhdrEOF:
        rc = -1;
        break;
@@ -458,12 +550,21 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
     size_t len = 0;
     size_t n, nn;
     fhdr_state_t state = afx->parse_state;
+    unsigned emplines = afx->empty;
 
     size = 100; /* FIXME: only used for testing (remove it)  */
 
     len = 2;   /* reserve 2 bytes for the length header */
-    size -= 2; /* and 2 for the term header */
+    size -= 3; /* and 1 for empline handling and 2 for the term header */
     while( !rc && len < size ) {
+       if( emplines ) {
+           while( emplines && len < size ) {
+               buf[len++] = '\r';
+               buf[len++] = '\n';
+               emplines--;
+           }
+           continue;
+       }
        if( afx->helpidx < afx->helplen ) { /* flush the last buffer */
            n = afx->helplen;
            for(nn=afx->helpidx; len < size && nn < n ; nn++ )
@@ -478,14 +579,19 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
        /* read a new one */
        n = DIM(afx->helpbuf);
        afx->helpidx = 0;
-       state = find_header( state, afx->helpbuf, &n, a, 0 );
+       state = find_header( state, afx->helpbuf, &n, a, 0, &emplines );
        switch( state) {
          case fhdrERROR:
+           invalid_armor();
+           break;
+
          case fhdrEOF:
            rc = -1;
            break;
 
          case fhdrCLEARSIG:
+           BUG();
+
          case fhdrREADClearsig:
          case fhdrREADClearsigNext:
            afx->helplen = n;
@@ -509,6 +615,7 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
     }
 
     afx->parse_state = state;
+    afx->empty = emplines;
     *retn = len;
     return rc;
 }
@@ -600,6 +707,8 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
                log_error("CRC error; %06lx - %06lx\n",
                                    (ulong)afx->crc, (ulong)mycrc);
            else {
+               rc = 0;
+             #if 0
                for(rc=0;!rc;) {
                    rc = 0 /*check_trailer( &fhdr, c )*/;
                    if( !rc ) {
@@ -615,6 +724,7 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
                    log_error("premature eof (in Trailer)\n");
                else
                    log_error("error in trailer line\n");
+             #endif
            }
        }
     }
@@ -641,6 +751,12 @@ armor_filter( void *opaque, int control,
     int  idx, idx2;
     size_t n=0;
     u32 crc;
+    static FILE *fp ;
+
+    if( !fp ) {
+       fp = fopen("armor.out", "w");
+       assert(fp);
+    }
 
     if( DBG_FILTER )
        log_debug("armor-filter: control: %d\n", control );
@@ -655,8 +771,8 @@ armor_filter( void *opaque, int control,
        *ret_len = n;
     }
     else if( control == IOBUFCTRL_UNDERFLOW ) {
-       if( size < 20 )
-           BUG(); /* supplied buffer maybe too short */
+       if( size < 30 )
+           BUG(); /* supplied buffer too short */
 
        if( afx->inp_eof ) {
            *ret_len = 0;
@@ -672,22 +788,36 @@ armor_filter( void *opaque, int control,
            if( afx->inp_bypass )
                ;
            else if( afx->faked ) {
-               /* the buffer is at least 20 bytes long, so it
-                * is easy to construct a packet */
-               buf[0] = 0xaf; /* old packet format, type 11, var length */
-               buf[1] = 0;    /* set the length header */
-               buf[2] = 6;
-               buf[3] = 't';  /* canonical text */
-               buf[4] = 0;    /* namelength */
-               buf[5] = buf[6] = buf[7] = buf[8] = 0; /* timestamp */
-               n = 9;
+               /* the buffer is at least 30 bytes long, so it
+                * is easy to construct the packets */
+
+               /* first a onepass signature packet */
+               buf[0] = 0x90; /* old packet forma, type 4, 1 length byte */
+               buf[1] = 13;   /* length */
+               buf[2] = 3;    /* version */
+               buf[3] = 0x01; /* sigclass 0x01 (data in canonical text mode)*/
+               buf[4] = 0;    /* digest algo (don't know) */
+               buf[5] = 0;    /* public key algo (don't know) */
+               memset(buf+6, 0, 8); /* don't know the keyid */
+               buf[14] = 1;   /* this is the last one */
+
+               /* followed by a plaintext packet */
+               buf[15] = 0xaf; /* old packet format, type 11, var length */
+               buf[16] = 0;    /* set the length header */
+               buf[17] = 6;
+               buf[18] = 't';  /* canonical text mode */
+               buf[19] = 0;    /* namelength */
+               memset(buf+20, 0, 4); /* timestamp */
+               n = 24;
            }
            else if( !rc )
                rc = radix64_read( afx, a, &n, buf, size );
        }
        else
            rc = radix64_read( afx, a, &n, buf, size );
-
+       if( n )
+           if( fwrite(buf, n, 1, fp ) != 1 )
+               BUG();
        *ret_len = n;
     }
     else if( control == IOBUFCTRL_FLUSH ) {
index b81a78d..b49ce28 100644 (file)
@@ -35,6 +35,7 @@ typedef struct {
     u32 crc;
     byte helpbuf[100];
     int  helpidx, helplen;
+    unsigned empty;    /* empty line counter */
     int faked;
     int parse_state;
     int inp_checked;   /* set if inp has been checked */
@@ -64,11 +65,10 @@ typedef struct {
 
 
 typedef struct {
-    size_t linesize;
-    byte *line;
-    size_t linelen;
-    size_t pos;
     int eof;
+    size_t idx;
+    size_t len;
+    byte buf[256];
 } text_filter_context_t;
 
 
index bbc4628..b648969 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -43,7 +43,7 @@
 
 enum cmd_values { aNull = 0,
     aSym, aStore, aEncr, aKeygen, aSign, aSignEncr,
-    aSignKey, aClearsig, aListPackets, aEditSig,
+    aSignKey, aClearsign, aListPackets, aEditSig,
     aKMode, aKModeC, aChangePass, aImport,
     aExport,
 aTest };
@@ -146,9 +146,9 @@ set_cmd( enum cmd_values *ret_cmd, enum cmd_values new_cmd )
        cmd = aSignEncr;
     else if( cmd == aKMode && new_cmd == aSym )
        cmd = aKModeC;
-    else if(   ( cmd == aSign     && new_cmd == aClearsig )
-            || ( cmd == aClearsig && new_cmd == aSign )  )
-       cmd = aClearsig;
+    else if(   ( cmd == aSign     && new_cmd == aClearsign )
+            || ( cmd == aClearsign && new_cmd == aSign )  )
+       cmd = aClearsign;
     else {
        log_error(_("conflicting commands\n"));
        g10_exit(2);
@@ -210,6 +210,7 @@ main( int argc, char **argv )
     { 536, "marginals-needed", 1, N_("(default is 3)")},
     { 537, "export", 0, N_("export all or the given keys") },
     { 538, "trustdb-name", 2, "\r" },
+    { 539, "clearsign", 0, N_("make a clear text signature") },
 
     {0} };
     ARGPARSE_ARGS pargs;
@@ -303,7 +304,7 @@ main( int argc, char **argv )
          case 'e': set_cmd( &cmd, aEncr); break;
          case 'b': detached_sig = 1; /* fall trough */
          case 's': set_cmd( &cmd, aSign );  break;
-         case 't': set_cmd( &cmd , aClearsig);  break;
+         case 't': set_cmd( &cmd , aClearsign);  break;
          case 'u': /* store the local users */
            sl = m_alloc( sizeof *sl + strlen(pargs.r.ret_str));
            strcpy(sl->d, pargs.r.ret_str);
@@ -362,6 +363,7 @@ main( int argc, char **argv )
          case 536: opt.marginals_needed = pargs.r.ret_int; break;
          case 537: set_cmd( &cmd, aExport); break;
          case 538: trustdb_name = pargs.r.ret_str; break;
+         case 539: set_cmd( &cmd, aClearsign); break;
          default : errors++; pargs.err = configfp? 1:2; break;
        }
     }
@@ -454,24 +456,24 @@ main( int argc, char **argv )
     switch( cmd ) {
       case aStore: /* only store the file */
        if( argc > 1 )
-           usage(1);
+           wrong_args(_("--store [filename]"));
        if( (rc = encode_store(fname)) )
-           log_error("encode_store('%s'): %s\n",
+           log_error("%s: store failed: %s\n",
                                    fname_print, g10_errstr(rc) );
        break;
 
       case aSym: /* encrypt the given file only with the symmetric cipher */
        if( argc > 1 )
-           usage(1);
+           wrong_args(_("--symmetric [filename]"));
        if( (rc = encode_symmetric(fname)) )
-           log_error("encode_symmetric('%s'): %s\n", fname_print, g10_errstr(rc) );
+           log_error("%s: symmetric encryption failed: %s\n", fname_print, g10_errstr(rc) );
        break;
 
       case aEncr: /* encrypt the given file */
        if( argc > 1 )
-           usage(1);
+           wrong_args(_("--encrypt [filename]"));
        if( (rc = encode_crypt(fname,remusr)) )
-           log_error("encode_crypt('%s'): %s\n", fname_print, g10_errstr(rc) );
+           log_error("%s: encryption failed: %s\n", fname_print, g10_errstr(rc) );
        break;
 
       case aSign: /* sign the given file */
@@ -482,20 +484,20 @@ main( int argc, char **argv )
        }
        else {
            if( argc > 1 )
-               usage(1);
+               wrong_args(_("--sign [filename]"));
            if( argc ) {
                sl = m_alloc_clear( sizeof *sl + strlen(fname));
                strcpy(sl->d, fname);
            }
        }
        if( (rc = sign_file( sl, detached_sig, locusr, 0, NULL, NULL)) )
-           log_error("sign_file: %s\n", g10_errstr(rc) );
+           log_error("signing failed: %s\n", g10_errstr(rc) );
        free_strlist(sl);
        break;
 
       case aSignEncr: /* sign and encrypt the given file */
        if( argc > 1 )
-           usage(1);
+           wrong_args(_("--sign --encrypt [filename]"));
        if( argc ) {
            sl = m_alloc_clear( sizeof *sl + strlen(fname));
            strcpy(sl->d, fname);
@@ -503,33 +505,40 @@ main( int argc, char **argv )
        else
            sl = NULL;
        if( (rc = sign_file(sl, detached_sig, locusr, 1, remusr, NULL)) )
-           log_error("sign_file('%s'): %s\n", fname_print, g10_errstr(rc) );
+           log_error("%s: sign+encrypt failed: %s\n", fname_print, g10_errstr(rc) );
        free_strlist(sl);
        break;
 
+      case aClearsign: /* make a clearsig */
+       if( argc > 1 )
+           wrong_args(_("--clearsign [filename]"));
+       if( (rc = clearsign_file(fname, locusr, NULL)) )
+           log_error("%s: clearsign failed: %s\n", fname_print, g10_errstr(rc) );
+       break;
+
 
       case aSignKey: /* sign the key given as argument */
        if( argc != 1 )
-           usage(1);
+           wrong_args(_("--sign-key username"));
        /* note: fname is the user id! */
        if( (rc = sign_key(fname, locusr)) )
-           log_error("sign_key('%s'): %s\n", fname_print, g10_errstr(rc) );
+           log_error("%s: sign key failed: %s\n", fname_print, g10_errstr(rc) );
        break;
 
       case aEditSig: /* Edit a key signature */
        if( argc != 1 )
-           usage(1);
+           wrong_args(_("--edit-sig username"));
        /* note: fname is the user id! */
        if( (rc = edit_keysigs(fname)) )
-           log_error("edit_keysig('%s'): %s\n", fname_print, g10_errstr(rc) );
+           log_error("%s: edit signature failed: %s\n", fname_print, g10_errstr(rc) );
        break;
 
       case aChangePass: /* Chnage the passphrase */
        if( argc > 1 ) /* no arg: use default, 1 arg use this one */
-           usage(1);
+           wrong_args(_("--change-passphrase [username]"));
        /* note: fname is the user id! */
        if( (rc = change_passphrase(fname)) )
-           log_error("change_passphrase('%s'): %s\n", fname_print,
+           log_error("%s: change passphrase failed: %s\n", fname_print,
                                                       g10_errstr(rc) );
        break;
 
@@ -562,18 +571,18 @@ main( int argc, char **argv )
            iobuf_close(a);
        }
        else
-           usage(1);
+           wrong_args(_("-k[v][v][v][c] [keyring]"));
        break;
 
       case aKeygen: /* generate a key (interactive) */
        if( argc )
-           usage(1);
+           wrong_args(_("--gen-key"));
        generate_keypair();
        break;
 
       case aImport:
        if( !argc  )
-           usage(1);
+           wrong_args(_("nyi"));
        for( ; argc; argc--, argv++ ) {
            rc = import_pubkeys( *argv );
            if( rc )
@@ -594,7 +603,7 @@ main( int argc, char **argv )
        opt.list_packets=1;
       default:
        if( argc > 1 )
-           usage(1);
+           wrong_args(_("[filename]"));
        if( !(a = iobuf_open(fname)) )
            log_fatal(_("can't open '%s'\n"), fname_print);
        if( !opt.no_armor ) {
index 5548f81..67091e7 100644 (file)
@@ -50,6 +50,7 @@ int encrypt_filter( void *opaque, int control,
 /*-- sign.c --*/
 int sign_file( STRLIST filenames, int detached, STRLIST locusr,
               int encrypt, STRLIST remusr, const char *outfile );
+int clearsign_file( const char *fname, STRLIST locusr, const char *outfile );
 int sign_key( const char *username, STRLIST locusr );
 int edit_keysigs( const char *username );
 int change_passphrase( const char *username );
index 70a50c6..cae7ddd 100644 (file)
@@ -274,6 +274,7 @@ proc_plaintext( CTX c, PACKET *pkt )
      * textmode filter (sigclass 0x01)
      */
     c->mfx.md = md_open( DIGEST_ALGO_RMD160, 0);
+    md_enable( c->mfx.md, DIGEST_ALGO_MD5 );
     rc = handle_plaintext( pt, &c->mfx );
     if( rc )
        log_error( "handle plaintext failed: %s\n", g10_errstr(rc));
@@ -325,6 +326,11 @@ do_check_sig( CTX c, KBNODE node )
     if( sig->sig_class == 0x00 ) {
        md = md_copy( c->mfx.md );
     }
+    else if( sig->sig_class == 0x01 ) {
+       /* how do we know that we have to hash the (already hashed) text
+        * in canonical mode ??? (calculating both modes???) */
+       md = md_copy( c->mfx.md );
+    }
     else if( (sig->sig_class&~3) == 0x10 ) { /* classes 0x10 .. 0x13 */
        if( c->cert->pkt->pkttype == PKT_PUBLIC_CERT ) {
            KBNODE n1 = find_kbparent( c->cert, node );
index 886bc66..f364d3b 100644 (file)
@@ -829,6 +829,8 @@ parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
     pktlen = 0;
 
     if( list_mode ) {
+       /* a value if 'c' is used by armor to indicate a faked packet
+        * it should be considered as 't' */
        printf(":literal data packet:\n"
               "\tmode %c, created %lu, name=\"",
                    mode >= ' ' && mode <'z'? mode : '?',
index ee9b982..d06b919 100644 (file)
@@ -301,6 +301,145 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
 
 
 
+static int
+write_dash_escaped( IOBUF inp, IOBUF out, MD_HANDLE md )
+{
+    int c;
+    int lastlf = 1;
+
+    while( (c = iobuf_get(inp)) != -1 ) {
+       /* Note: We don't escape "From " because the MUA should cope with it */
+       if( lastlf && c == '-' ) {
+           iobuf_put( out, c );
+           iobuf_put( out, ' ' );
+       }
+
+       md_putc(md, c );
+       iobuf_put( out, c );
+       lastlf = c == '\n';
+    }
+    return 0; /* fixme: add error handling */
+}
+
+
+/****************
+ * make a clear signature. note that opt.armor is not needed
+ */
+int
+clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
+{
+    armor_filter_context_t afx;
+    compress_filter_context_t zfx;
+    text_filter_context_t tfx;
+    MD_HANDLE textmd;
+    IOBUF inp = NULL, out = NULL;
+    PACKET pkt;
+    int rc = 0;
+    SKC_LIST skc_list = NULL;
+    SKC_LIST skc_rover = NULL;
+
+    memset( &afx, 0, sizeof afx);
+    memset( &zfx, 0, sizeof zfx);
+    memset( &tfx, 0, sizeof tfx);
+    init_packet( &pkt );
+
+    if( (rc=build_skc_list( locusr, &skc_list, 1 )) )
+       goto leave;
+
+    /* prepare iobufs */
+    if( !(inp = iobuf_open(fname)) ) {
+       log_error("can't open %s: %s\n", fname? fname: "[stdin]",
+                                       strerror(errno) );
+       rc = G10ERR_OPEN_FILE;
+       goto leave;
+    }
+
+    if( outfile ) {
+       if( !(out = iobuf_create( outfile )) ) {
+           log_error("can't create %s: %s\n", outfile, strerror(errno) );
+           rc = G10ERR_CREATE_FILE;
+           goto leave;
+       }
+       else if( opt.verbose )
+           log_info("writing to '%s'\n", outfile );
+    }
+    else if( !(out = open_outfile( fname, 1 )) ) {
+       rc = G10ERR_CREATE_FILE;
+       goto leave;
+    }
+
+    iobuf_writestr(out, "-----BEGIN PGP SIGNED MESSAGE-----\n\n" );
+
+    textmd = md_open(DIGEST_ALGO_RMD160, 0);
+    iobuf_push_filter( inp, text_filter, &tfx );
+    rc = write_dash_escaped( inp, out, textmd );
+    if( rc )
+       goto leave;
+
+    iobuf_writestr(out, "\n\n" );
+    afx.what = 2;
+    iobuf_push_filter( out, armor_filter, &afx );
+
+    /* loop over the secret certificates */
+    for( skc_rover = skc_list; skc_rover; skc_rover = skc_rover->next ) {
+       PKT_secret_cert *skc;
+       PKT_signature *sig;
+       MD_HANDLE md;
+
+       skc = skc_rover->skc;
+
+       /* build the signature packet */
+       sig = m_alloc_clear( sizeof *sig );
+       sig->pubkey_algo = skc->pubkey_algo;
+       sig->timestamp = make_timestamp();
+       sig->sig_class = 0x01;
+
+       md = md_copy( textmd );
+       md_putc( md, sig->sig_class );
+       {   u32 a = sig->timestamp;
+           md_putc( md, (a >> 24) & 0xff );
+           md_putc( md, (a >> 16) & 0xff );
+           md_putc( md, (a >>  8) & 0xff );
+           md_putc( md,  a        & 0xff );
+       }
+       md_final( md );
+
+       if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
+           g10_elg_sign( skc, sig, md, DIGEST_ALGO_RMD160 );
+       else if( sig->pubkey_algo == PUBKEY_ALGO_RSA )
+           g10_rsa_sign( skc, sig, md, DIGEST_ALGO_RMD160 );
+       else
+           BUG();
+
+       md_close( md );
+
+       /* and write it */
+       init_packet(&pkt);
+       pkt.pkttype = PKT_SIGNATURE;
+       pkt.pkt.signature = sig;
+       rc = build_packet( out, &pkt );
+       free_packet( &pkt );
+       if( rc ) {
+           log_error("build signature packet failed: %s\n", g10_errstr(rc) );
+           goto leave;
+       }
+    }
+
+
+  leave:
+    if( rc )
+       iobuf_cancel(out);
+    else
+       iobuf_close(out);
+    iobuf_close(inp);
+    md_close( textmd );
+    release_skc_list( skc_list );
+    return rc;
+}
+
+
+
+
 static void
 show_fingerprint( PKT_public_cert *pkc )
 {
index baae1e9..47cc7bd 100644 (file)
@@ -49,6 +49,7 @@ write_status( int no )
       case STATUS_GOODSIG: s = "GOODSIG\n"; break;
       case STATUS_BADSIG : s = "BADSIG\n"; break;
       case STATUS_ERRSIG : s = "ERRSIG\n"; break;
+      case STATUS_BADARMOR : s = "BADARMOR\n"; break;
       default: s = "?\n"; break;
     }
 
index 55eef32..f8e3f60 100644 (file)
@@ -30,6 +30,7 @@
 #define STATUS_ERRSIG   6
 
 
+#define STATUS_BADARMOR  7
 
 
 
index e57b429..4734fe4 100644 (file)
 #include "filter.h"
 
 
+
+
+static int
+read_line( byte *buf, size_t *r_buflen, IOBUF a )
+{
+    int c;
+    int rc = 0;
+    byte *p;
+    size_t buflen;
+    int no_lf=0;
+    size_t n;
+
+    buflen = *r_buflen;
+    assert(buflen >= 20 );
+    buflen -= 3; /* leave some room for CR,LF and one extra */
+
+    for(c=0, n=0; n < buflen && (c=iobuf_get2(a)) != -1 && c != '\n'; )
+       buf[n++] = c;
+    buf[n] = 0;
+    if( c == -1 )
+       rc = -1;
+    else if( c != '\n' ) {
+       IOBUF b = iobuf_temp();
+       while( (c=iobuf_get2(a)) != -1 && c != '\n' ) {
+           iobuf_put(b,c);
+           if( c != ' ' && c != '\t' && c != '\r' )
+               break;
+       }
+       if( c == '\n' ) { /* okay we can skip the rest of the line */
+           iobuf_close(b);
+       }
+       else {
+           iobuf_unget_and_close_temp(a,b);
+           no_lf = 1;
+       }
+    }
+
+    if( !no_lf ) {
+       /* append CR,LF after removing trailing wspaces */
+       for(p=buf+n-1; n; n--, p-- ) {
+           assert( *p != '\n' );
+           if( *p != ' ' && *p != '\t' && *p != '\r' ) {
+               p[1] = '\r';
+               p[2] = '\n';
+               n += 2;
+               break;
+           }
+       }
+       if( !n ) {
+           buf[0] = '\r';
+           buf[1] = '\n';
+           n = 2;
+       }
+    }
+
+
+    *r_buflen = n;
+    return rc;
+}
+
+
+
+
 /****************
  * The filter is used to make canonical text: Lines are terminated by
  * CR, LF, trailing white spaces are removed.
@@ -42,60 +105,31 @@ text_filter( void *opaque, int control,
 {
     size_t size = *ret_len;
     text_filter_context_t *tfx = opaque;
-    int i, c, rc=0;
-    byte *p;
+    int rc=0;
+    size_t len, n, nn;
 
     if( control == IOBUFCTRL_UNDERFLOW ) {
-       for(i=0; i < size; i++ ) {
-           if( !tfx->linelen && !tfx->eof ) { /* read a complete line */
-               for(;;) {
-                   if( (c = iobuf_get(a)) == -1 ) {
-                       tfx->eof=1;
-                       break;
-                   }
-                   if( c == '\n' )
-                       break;
-                   if( tfx->linelen >= tfx->linesize ) {
-                       tfx->linesize += 500;
-                       tfx->line = m_realloc( tfx->line, tfx->linesize );
-                   }
-                   tfx->line[tfx->linelen++] = c;
-               }
-               /* remove trailing white spaces */
-               p = tfx->line + tfx->linelen - 1;
-               for( ; p >= tfx->line; p--, tfx->linelen-- ) {
-                   if( *p != ' ' && *p == '\t' && *p != '\r' )
-                       break;
-               }
-               if( tfx->linelen+2 >= tfx->linesize ) {
-                   tfx->linesize += 10;
-                   tfx->line = m_realloc( tfx->line, tfx->linesize );
-               }
-               tfx->line[tfx->linelen++] = '\r';
-               tfx->line[tfx->linelen++] = '\n';
-               tfx->pos=0;
+       assert( size > 30 );
+       len = 0;
+       while( !rc && len < size ) {
+           if( tfx->idx < tfx->len ) { /* flush the last buffer */
+               n = tfx->len;
+               for(nn=tfx->idx; len < size && nn < n ; nn++ )
+                   buf[len++] = tfx->buf[nn];
+               tfx->idx = nn;
+               continue;
            }
-           if( tfx->pos < tfx->linelen )
-               buf[i] = tfx->line[tfx->pos++];
-           else if( tfx->eof )
-               break;
-           else
-               tfx->linelen = 0;
+           if( tfx->eof ) {
+               rc = -1;
+               continue;
+           }
+           n = DIM(tfx->buf);
+           tfx->idx = 0;
+           if( read_line( tfx->buf, &n, a ) == -1 )
+               tfx->eof = 1;
+           tfx->len = n;
        }
-       if( !i )
-           rc = -1;
-       *ret_len = i;
-    }
-    else if( control == IOBUFCTRL_INIT ) {
-       tfx->linesize = 500;
-       tfx->line = m_alloc(tfx->linesize);
-       tfx->linelen = 0;
-       tfx->pos = 0;
-       tfx->eof = 0;
-    }
-    else if( control == IOBUFCTRL_FREE ) {
-       m_free( tfx->line );
-       tfx->line = NULL;
+       *ret_len = len;
     }
     else if( control == IOBUFCTRL_DESC )
        *(char**)buf = "text_filter";
index 81e23f2..e5ce81a 100644 (file)
@@ -56,6 +56,12 @@ struct iobuf_struct {
     const char *desc;
     void *opaque;      /* can be used to hold any information   */
                       /* this value is copied to all instances */
+    struct {
+       size_t size;   /* allocated size */
+       size_t start;  /* number of invalid bytes at the begin of the buffer */
+       size_t len;    /* currently filled to this size */
+       byte *buf;
+    } unget;
 };
 
 int iobuf_debug_mode;
@@ -88,6 +94,7 @@ int  iobuf_writestr(IOBUF a, const char *buf );
 
 int  iobuf_write_temp( IOBUF a, IOBUF temp );
 size_t iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen );
+void iobuf_unget_and_close_temp( IOBUF a, IOBUF temp );
 
 u32 iobuf_get_filelength( IOBUF a );
 const char *iobuf_get_fname( IOBUF a );
@@ -106,6 +113,10 @@ int  iobuf_in_block_mode( IOBUF a );
        iobuf_readbyte((a)) : ( (a)->nbytes++, (a)->d.buf[(a)->d.start++] ) )
 #define iobuf_get_noeof(a)    (iobuf_get((a))&0xff)
 
+/* use this if you have ungetted stuff */
+#define iobuf_get2(a)  \
+     ( ( (a)->unget.buf || (a)->nlimit || (a)->d.start >= (a)->d.len )?  \
+       iobuf_readbyte((a)) : ( (a)->nbytes++, (a)->d.buf[(a)->d.start++] ) )
 
 /* write a byte to the iobuf and return true on write error
  * This macro does only write the low order byte
index 72a14f5..d429d4c 100644 (file)
@@ -700,6 +700,15 @@ iobuf_readbyte(IOBUF a)
 {
     int c;
 
+    /* nlimit does not work together with unget */
+    /* nbytes is also not valid! */
+    if( a->unget.buf ) {
+       if( a->unget.start < a->unget.len )
+           return a->unget.buf[a->unget.start++];
+       m_free(a->unget.buf);
+       a->unget.buf = NULL;
+    }
+
     if( a->nlimit && a->nbytes >= a->nlimit )
        return -1; /* forced EOF */
 
@@ -770,6 +779,27 @@ iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen )
     return n;
 }
 
+/****************
+ * unget the contents of the temp io stream to A and close temp
+ * Could be optimized!!
+ */
+void
+iobuf_unget_and_close_temp( IOBUF a, IOBUF temp )
+{
+    if( a->unget.buf ) {
+       if( a->unget.start < a->unget.len )
+           log_fatal("cannot do any more ungets on this buffer\n");
+       /* not yet cleaned up; do it now */
+       m_free(a->unget.buf);
+       a->unget.buf = NULL;
+    }
+    a->unget.size = temp->d.len;
+    a->unget.buf = m_alloc( a->unget.size );
+    a->unget.len = temp->d.len;
+    memcpy( a->unget.buf, temp->d.buf, a->unget.len );
+    iobuf_close(temp);
+}
+
 
 /****************
  * Set a limit, how much bytes may be read from the input stream A.