* keygen.c (ask_key_flags): New. (ask_algo): Call it here in --expert mode
[gnupg.git] / g10 / armor.c
index 98559d0..6d27472 100644 (file)
@@ -1,6 +1,6 @@
 /* armor.c - Armor flter
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
- *                                             Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
+ *               2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -39,9 +39,9 @@
 #include "i18n.h"
 
 #ifdef HAVE_DOSISH_SYSTEM
-  #define LF "\r\n"
+#define LF "\r\n"
 #else
-  #define LF "\n"
+#define LF "\n"
 #endif
 
 #define MAX_LINELEN 20000
@@ -248,16 +248,12 @@ parse_hash_header( const char *line )
            found |= 2;
        else if( !strncmp( s, "MD5", s2-s ) )
            found |= 4;
-       else if( !strncmp( s, "TIGER192", s2-s ) )
-           found |= 8;
-       else if( !strncmp( s, "TIGER", s2-s ) ) /* used by old versions */
-           found |= 8;
        else if( !strncmp( s, "SHA256", s2-s ) )
-           found |= 16;
+           found |= 8;
        else if( !strncmp( s, "SHA384", s2-s ) )
-           found |= 32;
+           found |= 16;
        else if( !strncmp( s, "SHA512", s2-s ) )
-           found |= 64;
+           found |= 32;
        else
            return 0;
        for(; *s2 && (*s2==' ' || *s2 == '\t'); s2++ )
@@ -468,7 +464,8 @@ check_input( armor_filter_context_t *afx, IOBUF a )
     return rc;
 }
 
-
+#define PARTIAL_CHUNK 512
+#define PARTIAL_POW   9
 
 /****************
  * Fake a literal data packet and wait for the next armor line
@@ -484,19 +481,31 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
     int lastline = 0;
     unsigned maxlen, n;
     byte *p;
+    byte tempbuf[PARTIAL_CHUNK];
+    size_t tempbuf_len=0;
 
-    len = 2;   /* reserve 2 bytes for the length header */
-    size -= 2; /* and 2 for the terminating header */
-    while( !rc && len < size ) {
+    while( !rc && size-len>=(PARTIAL_CHUNK+1)) {
        /* copy what we have in the line buffer */
        if( afx->faked == 1 )
            afx->faked++; /* skip the first (empty) line */
-       else {
-           while( len < size && afx->buffer_pos < afx->buffer_len )
-               buf[len++] = afx->buffer[afx->buffer_pos++];
-           if( len >= size )
+       else
+         {
+           /* It's full, so write this partial chunk */
+           if(tempbuf_len==PARTIAL_CHUNK)
+             {
+               buf[len++]=0xE0+PARTIAL_POW;
+               memcpy(&buf[len],tempbuf,PARTIAL_CHUNK);
+               len+=PARTIAL_CHUNK;
+               tempbuf_len=0;
                continue;
-       }
+             }
+
+           while( tempbuf_len < PARTIAL_CHUNK
+                  && afx->buffer_pos < afx->buffer_len )
+             tempbuf[tempbuf_len++] = afx->buffer[afx->buffer_pos++];
+           if( tempbuf_len==PARTIAL_CHUNK )
+             continue;
+         }
 
        /* read the next line */
        maxlen = MAX_LINELEN;
@@ -553,7 +562,7 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
                    ; /* this is okay */
                else {
                    if( type != BEGIN_SIGNATURE ) {
-                       log_info(_("unexpected armor:"));
+                       log_info(_("unexpected armor: "));
                        print_string( stderr, p, n, 0 );
                        putc('\n', stderr);
                    }
@@ -564,13 +573,17 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
        }
     }
 
-    buf[0] = (len-2) >> 8;
-    buf[1] = (len-2);
     if( lastline ) { /* write last (ending) length header */
-       if( buf[0] || buf[1] ) { /* only if we have some text */
-           buf[len++] = 0;
-           buf[len++] = 0;
-       }
+        if(tempbuf_len<192)
+         buf[len++]=tempbuf_len;
+       else
+         {
+           buf[len++]=((tempbuf_len-192)/256) + 192;
+           buf[len++]=(tempbuf_len-192) % 256;
+         }
+       memcpy(&buf[len],tempbuf,tempbuf_len);
+       len+=tempbuf_len;
+
        rc = 0;
        afx->faked = 0;
        afx->in_cleartext = 0;
@@ -679,7 +692,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) {
@@ -758,13 +771,17 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
            if( c == -1 ) {
                log_info(_("premature eof (in CRC)\n"));
                rc = invalid_crc();
-                           }
+           }
+           else if( idx == 0 ) {
+               /* No CRC at all is legal ("MAY") */
+               rc=0;
+           }
            else if( idx != 4 ) {
                log_info(_("malformed CRC\n"));
                rc = invalid_crc();
            }
            else if( mycrc != afx->crc ) {
-                log_info (_("CRC error; %06lx - %06lx\n"),
+                log_info (_("CRC error; %06lX - %06lX\n"),
                                    (ulong)afx->crc, (ulong)mycrc);
                 rc = invalid_crc();
            }
@@ -773,7 +790,7 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
                 /* FIXME: Here we should emit another control packet,
                  * so that we know in mainproc that we are processing
                  * a clearsign message */
-             #if 0
+#if 0
                for(rc=0;!rc;) {
                    rc = 0 /*check_trailer( &fhdr, c )*/;
                    if( !rc ) {
@@ -784,14 +801,14 @@ 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"));
                    rc = G10ERR_INVALID_ARMOR;
                }
-             #endif
+#endif
            }
        }
     }
@@ -817,14 +834,14 @@ armor_filter( void *opaque, int control,
     int  idx, idx2;
     size_t n=0;
     u32 crc;
-  #if 0
+#if 0
     static FILE *fp ;
 
     if( !fp ) {
        fp = fopen("armor.out", "w");
        assert(fp);
     }
-  #endif
+#endif
 
     if( DBG_FILTER )
        log_debug("armor-filter: control: %d\n", control );
@@ -846,9 +863,10 @@ armor_filter( void *opaque, int control,
        *ret_len = n;
     }
     else if( control == IOBUFCTRL_UNDERFLOW ) {
-        /* We need some space for the faked packet.  The minmum required
-         * size is ~18 + length of the session marker */
-       if( size < 50 ) 
+        /* We need some space for the faked packet.  The minmum
+         * required size is the PARTIAL_CHUNK size plus a byte for the
+         * length itself */
+       if( size < PARTIAL_CHUNK+1 ) 
            BUG(); /* supplied buffer too short */
 
        if( afx->faked )
@@ -885,7 +903,7 @@ armor_filter( void *opaque, int control,
                        afx->pgp2mode = 1;
                }
                n=0;
-                /* first a gpg control packet */
+                /* First a gpg control packet... */
                 buf[n++] = 0xff; /* new format, type 63, 1 length byte */
                 n++;   /* see below */
                 memcpy(buf+n, sesmark, sesmarklen ); n+= sesmarklen;
@@ -898,21 +916,23 @@ armor_filter( void *opaque, int control,
                 if( hashes & 4 )
                     buf[n++] = DIGEST_ALGO_MD5;
                 if( hashes & 8 )
-                    buf[n++] = DIGEST_ALGO_TIGER;
-                if( hashes & 16 )
                     buf[n++] = DIGEST_ALGO_SHA256;
-                if( hashes & 32 )
+                if( hashes & 16 )
                     buf[n++] = DIGEST_ALGO_SHA384;
-                if( hashes & 64 )
+                if( hashes & 32 )
                     buf[n++] = DIGEST_ALGO_SHA512;
                 buf[1] = n - 2;
 
-               /* followed by a plaintext packet */
-               buf[n++] = 0xaf; /* old packet format, type 11, var length */
-               buf[n++] = 0;    /* set the length header */
-               buf[n++] = 6;
+               /* ...followed by an invented plaintext packet.
+                  Amusingly enough, this packet is not compliant with
+                  2440 as the initial partial length is less than 512
+                  bytes.  Of course, we'll accept it anyway ;) */
+
+               buf[n++] = 0xCB; /* new packet format, type 11 */
+               buf[n++] = 0xE1; /* 2^1 == 2 bytes */
                buf[n++] = 't';  /* canonical text mode */
                buf[n++] = 0;    /* namelength */
+               buf[n++] = 0xE2; /* 2^2 == 4 more bytes */
                memset(buf+n, 0, 4); /* timestamp */
                n += 4;
            }
@@ -921,16 +941,17 @@ armor_filter( void *opaque, int control,
        }
        else
            rc = radix64_read( afx, a, &n, buf, size );
-      #if 0
+#if 0
        if( n )
            if( fwrite(buf, n, 1, fp ) != 1 )
                BUG();
-      #endif
+#endif
        *ret_len = n;
     }
     else if( control == IOBUFCTRL_FLUSH && !afx->cancel ) {
        if( !afx->status ) { /* write the header line */
            const char *s;
+           STRLIST comment=opt.comments;
 
            if( afx->what >= DIM(head_strings) )
                log_bug("afx->what=%d", afx->what);
@@ -941,29 +962,30 @@ armor_filter( void *opaque, int control,
                iobuf_writestr(a, "Version: GnuPG v"  VERSION " ("
                                              PRINTABLE_OS_NAME ")" LF );
 
-           /* write the comment string or a default one */
-           s = opt.comment_string;
-           if( s && *s ) {
+           /* write the comment strings */
+           for(s=comment->d;comment;comment=comment->next,s=comment->d)
+             {
                iobuf_writestr(a, "Comment: " );
-               for( ; *s; s++ ) {
+               for( ; *s; s++ )
+                 {
                    if( *s == '\n' )
-                       iobuf_writestr(a, "\\n" );
+                     iobuf_writestr(a, "\\n" );
                    else if( *s == '\r' )
-                       iobuf_writestr(a, "\\r" );
+                     iobuf_writestr(a, "\\r" );
                    else if( *s == '\v' )
-                       iobuf_writestr(a, "\\v" );
+                     iobuf_writestr(a, "\\v" );
                    else
-                       iobuf_put(a, *s );
-               }
+                     iobuf_put(a, *s );
+                 }
                iobuf_writestr(a, LF );
-           }
+             }
 
            if ( afx->hdrlines ) {
                 for ( s = afx->hdrlines; *s; s++ ) {
-                  #ifdef HAVE_DOSISH_SYSTEM
+#ifdef HAVE_DOSISH_SYSTEM
                     if ( *s == '\n' )
                         iobuf_put( a, '\r');
-                  #endif
+#endif
                     iobuf_put(a, *s );
                 }
             }
@@ -1255,7 +1277,7 @@ unarmor_pump (UnarmorPump x, int c)
         {
             int c2;
             if( (c = asctobin[(c2=c)]) == 255 ) {
-                log_error(_("invalid radix64 character %02x skipped\n"), c2);
+                log_error(_("invalid radix64 character %02X skipped\n"), c2);
                 break;
             }
         }
@@ -1292,7 +1314,7 @@ unarmor_pump (UnarmorPump x, int c)
         if( (c = asctobin[c]) == 255 ) {
             rval = -1; /* ready */
             if( x->crc != x->mycrc ) {
-                log_info (_("CRC error; %06lx - %06lx\n"),
+                log_info (_("CRC error; %06lX - %06lX\n"),
                           (ulong)x->crc, (ulong)x->mycrc);
                 if ( invalid_crc() )
                     rval = -3;