See ChangeLog: Wed Dec 23 13:34:22 CET 1998 Werner Koch
[gnupg.git] / g10 / build-packet.c
index b8acc57..5b952f1 100644 (file)
@@ -1,14 +1,14 @@
 /* build-packet.c - assemble packets and write them
  *     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.
@@ -47,10 +47,11 @@ static int do_compressed( IOBUF out, int ctb, PKT_compressed *cd );
 static int do_signature( IOBUF out, int ctb, PKT_signature *sig );
 static int do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops );
 
-static int calc_header_length( u32 len );
+static int calc_header_length( u32 len, int new_ctb );
 static int write_16(IOBUF inp, u16 a);
 static int write_32(IOBUF inp, u32 a);
 static int write_header( IOBUF out, int ctb, u32 len );
+static int write_sign_packet_header( IOBUF out, int ctb, u32 len );
 static int write_header2( IOBUF out, int ctb, u32 len, int hdrlen, int blkmode );
 static int write_new_header( IOBUF out, int ctb, u32 len, int hdrlen );
 static int write_version( IOBUF out, int ctb );
@@ -134,11 +135,13 @@ u32
 calc_packet_length( PACKET *pkt )
 {
     u32 n=0;
+    int new_ctb = 0;
 
     assert( pkt->pkt.generic );
     switch( pkt->pkttype ) {
       case PKT_PLAINTEXT:
        n = calc_plaintext( pkt->pkt.plaintext );
+       new_ctb = pkt->pkt.plaintext->new_ctb;
        break;
       case PKT_USER_ID:
       case PKT_COMMENT:
@@ -155,7 +158,8 @@ calc_packet_length( PACKET *pkt )
        log_bug("invalid packet type in calc_packet_length()");
        break;
     }
-    n += calc_header_length(n);
+
+    n += calc_header_length(n, new_ctb);
     return n;
 }
 
@@ -205,8 +209,14 @@ do_public_key( IOBUF out, int ctb, PKT_public_key *pk )
     else
        iobuf_put( a, pk->version );
     write_32(a, pk->timestamp );
-    if( pk->version < 4 )
-       write_16(a, pk->valid_days );
+    if( pk->version < 4 ) {
+       u16 ndays;
+       if( pk->expiredate )
+           ndays = (u16)((pk->expiredate - pk->timestamp) / 86400L);
+       else
+           ndays = 0;
+       write_16(a, ndays );
+    }
     iobuf_put(a, pk->pubkey_algo );
     n = pubkey_get_npkey( pk->pubkey_algo );
     if( !n )
@@ -276,12 +286,18 @@ do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
     else
        iobuf_put( a, sk->version );
     write_32(a, sk->timestamp );
-    if( sk->version < 4 )
-       write_16(a, sk->valid_days );
+    if( sk->version < 4 ) {
+       u16 ndays;
+       if( sk->expiredate )
+           ndays = (u16)((sk->expiredate - sk->timestamp) / 86400L);
+       else
+           ndays = 0;
+       write_16(a, 0 );
+    }
     iobuf_put(a, sk->pubkey_algo );
     nskey = pubkey_get_nskey( sk->pubkey_algo );
     npkey = pubkey_get_npkey( sk->pubkey_algo );
-    if( npkey ) {
+    if( !npkey ) {
        write_fake_data( a, sk->skey[0] );
        goto leave;
     }
@@ -290,7 +306,8 @@ do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
     for(i=0; i < npkey; i++ )
        mpi_write(a, sk->skey[i] );
     if( sk->is_protected ) {
-       if( is_RSA(sk->pubkey_algo) && sk->version < 4 ) {
+       if( is_RSA(sk->pubkey_algo) && sk->version < 4
+                                   && !sk->protect.s2k.mode ) {
            iobuf_put(a, sk->protect.algo );
            iobuf_write(a, sk->protect.iv, 8 );
        }
@@ -300,18 +317,26 @@ do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
            iobuf_put(a, sk->protect.s2k.mode );
            iobuf_put(a, sk->protect.s2k.hash_algo );
            if( sk->protect.s2k.mode == 1
-               || sk->protect.s2k.mode == 4 )
+               || sk->protect.s2k.mode == 3 )
                iobuf_write(a, sk->protect.s2k.salt, 8 );
-           if( sk->protect.s2k.mode == 4 )
-               write_32(a, sk->protect.s2k.count );
+           if( sk->protect.s2k.mode == 3 )
+               iobuf_put(a, sk->protect.s2k.count );
            iobuf_write(a, sk->protect.iv, 8 );
        }
     }
     else
        iobuf_put(a, 0 );
-    for(   ; i < nskey; i++ )
-       mpi_write(a, sk->skey[i] );
-    write_16(a, sk->csum );
+    if( sk->is_protected && sk->version >= 4 ) {
+       byte *p;
+       assert( mpi_is_opaque( sk->skey[npkey] ) );
+       p = mpi_get_opaque( sk->skey[npkey], &i );
+       iobuf_write(a, p, i );
+    }
+    else {
+       for(   ; i < nskey; i++ )
+           mpi_write(a, sk->skey[i] );
+       write_16(a, sk->csum );
+    }
 
   leave:
     write_header2(out, ctb, iobuf_get_temp_length(a), sk->hdrbytes, 1 );
@@ -330,17 +355,17 @@ do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc )
 
     assert( enc->version == 4 );
     switch( enc->s2k.mode ) {
-      case 0: case 1: case 4: break;
+      case 0: case 1: case 3: break;
       default: log_bug("do_symkey_enc: s2k=%d\n", enc->s2k.mode );
     }
     iobuf_put( a, enc->version );
     iobuf_put( a, enc->cipher_algo );
     iobuf_put( a, enc->s2k.mode );
     iobuf_put( a, enc->s2k.hash_algo );
-    if( enc->s2k.mode == 1 || enc->s2k.mode == 4 ) {
+    if( enc->s2k.mode == 1 || enc->s2k.mode == 3 ) {
        iobuf_write(a, enc->s2k.salt, 8 );
-       if( enc->s2k.mode == 4 )
-           write_32(a, enc->s2k.count);
+       if( enc->s2k.mode == 3 )
+           iobuf_put(a, enc->s2k.count);
     }
     if( enc->seskeylen )
        iobuf_write(a, enc->seskey, enc->seskeylen );
@@ -364,8 +389,14 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
     IOBUF a = iobuf_temp();
 
     write_version( a, ctb );
-    write_32(a, enc->keyid[0] );
-    write_32(a, enc->keyid[1] );
+    if( enc->throw_keyid ) {
+       write_32(a, 0 );  /* don't tell Eve who can decrypt the message */
+       write_32(a, 0 );
+    }
+    else {
+       write_32(a, enc->keyid[0] );
+       write_32(a, enc->keyid[1] );
+    }
     iobuf_put(a,enc->pubkey_algo );
     n = pubkey_get_nenc( enc->pubkey_algo );
     if( !n )
@@ -669,7 +700,10 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
     for(i=0; i < n; i++ )
        mpi_write(a, sig->data[i] );
 
-    write_header(out, ctb, iobuf_get_temp_length(a) );
+    if( is_RSA(sig->pubkey_algo) && sig->version < 4 )
+       write_sign_packet_header(out, ctb, iobuf_get_temp_length(a) );
+    else
+       write_header(out, ctb, iobuf_get_temp_length(a) );
     if( iobuf_write_temp( out, a ) )
        rc = G10ERR_WRITE_FILE;
 
@@ -726,16 +760,25 @@ write_32(IOBUF out, u32 a)
  * calculate the length of a header
  */
 static int
-calc_header_length( u32 len )
+calc_header_length( u32 len, int new_ctb )
 {
     if( !len )
        return 1; /* only the ctb */
-    else if( len < 256 )
+
+    if( new_ctb ) {
+       if( len < 192 )
+           return 2;
+       if( len < 8384 )
+           return 3;
+       else
+           return 6;
+    }
+    if( len < 256 )
        return 2;
-    else if( len < 65536 )
+    if( len < 65536 )
        return 3;
-    else
-       return 5;
+
+    return 5;
 }
 
 /****************
@@ -747,6 +790,18 @@ write_header( IOBUF out, int ctb, u32 len )
     return write_header2( out, ctb, len, 0, 1 );
 }
 
+
+static int
+write_sign_packet_header( IOBUF out, int ctb, u32 len )
+{
+    /* work around a bug in the pgp read function for signature packets,
+     * which are not correctly coded and silently assume at some
+     * point 2 byte length headers.*/
+    iobuf_put(out, 0x89 );
+    iobuf_put(out, len >> 8 );
+    return iobuf_put(out, len ) == -1 ? -1:0;
+}
+
 /****************
  * if HDRLEN is > 0, try to build a header of this length.
  * we need this, so that we can hash packets without reading them again.