2010-06-08 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / g10 / build-packet.c
index e1aeae2..37922d9 100644 (file)
@@ -1,12 +1,12 @@
 /* build-packet.c - assemble packets and write them
 /* build-packet.c - assemble packets and write them
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- *               2005 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ *               2006 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  *
  * This file is part of GnuPG.
  *
  * 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
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -15,8 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
  */
 
 #include <config.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+#include <ctype.h>
 
 
+#include "gpg.h"
 #include "packet.h"
 #include "packet.h"
-#include "errors.h"
+#include "status.h"
 #include "iobuf.h"
 #include "iobuf.h"
-#include "mpi.h"
 #include "util.h"
 #include "cipher.h"
 #include "util.h"
 #include "cipher.h"
-#include "memory.h"
+#include "i18n.h"
 #include "options.h"
 
 static int do_user_id( IOBUF out, int ctb, PKT_user_id *uid );
 #include "options.h"
 
 static int do_user_id( IOBUF out, int ctb, PKT_user_id *uid );
@@ -148,6 +148,33 @@ build_packet( IOBUF out, PACKET *pkt )
     return rc;
 }
 
     return rc;
 }
 
+
+/*
+ * Write the mpi A to OUT.
+ */
+static int
+mpi_write (iobuf_t out, gcry_mpi_t a)
+{
+  char buffer[(MAX_EXTERN_MPI_BITS+7)/8+2]; /* 2 is for the mpi length. */
+  size_t nbytes;
+  int rc;
+
+  nbytes = DIM(buffer);
+  rc = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a );
+  if( !rc )
+    rc = iobuf_write( out, buffer, nbytes );
+  else if (gpg_err_code(rc) == GPG_ERR_TOO_SHORT )
+    {
+      log_info ("mpi too large (%u bits)\n", gcry_mpi_get_nbits (a));
+      /* The buffer was too small. We better tell the user about the MPI. */
+      rc = gpg_error (GPG_ERR_TOO_LARGE);
+    }
+
+  return rc;
+}
+
+
+
 /****************
  * calculate the length of a packet described by PKT
  */
 /****************
  * calculate the length of a packet described by PKT
  */
@@ -185,31 +212,32 @@ calc_packet_length( PACKET *pkt )
 }
 
 static void
 }
 
 static void
-write_fake_data( IOBUF out, MPI a )
+write_fake_data (IOBUF out, gcry_mpi_t a)
 {
 {
-    if( a ) {
-        unsigned int i;
-       void *p;
-
-       p = mpi_get_opaque( a, &i );
-       iobuf_write( out, p, i );
+  if (a) 
+    {
+      unsigned int n;
+      void *p;
+      
+      p = gcry_mpi_get_opaque ( a, &n );
+      iobuf_write (out, p, (n+7)/8 );
     }
 }
 
 static int
 do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
 {
     }
 }
 
 static int
 do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
 {
+    int rc;
+
     if( uid->attrib_data )
       {
        write_header(out, ctb, uid->attrib_len);
     if( uid->attrib_data )
       {
        write_header(out, ctb, uid->attrib_len);
-       if( iobuf_write( out, uid->attrib_data, uid->attrib_len ) )
-         return G10ERR_WRITE_FILE;
+       rc = iobuf_write( out, uid->attrib_data, uid->attrib_len );
       }
     else
       {
         write_header2( out, ctb, uid->len, 2 );
       }
     else
       {
         write_header2( out, ctb, uid->len, 2 );
-       if( iobuf_write( out, uid->name, uid->len ) )
-         return G10ERR_WRITE_FILE;
+       rc = iobuf_write( out, uid->name, uid->len );
       }
     return 0;
 }
       }
     return 0;
 }
@@ -217,173 +245,195 @@ do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
 static int
 do_public_key( IOBUF out, int ctb, PKT_public_key *pk )
 {
 static int
 do_public_key( IOBUF out, int ctb, PKT_public_key *pk )
 {
-    int rc = 0;
-    int n, i;
-    IOBUF a = iobuf_temp();
-
-    if( !pk->version )
-       iobuf_put( a, 3 );
-    else
-       iobuf_put( a, pk->version );
-    write_32(a, pk->timestamp );
-    if( pk->version < 4 ) {
-       u16 ndays;
-       if( pk->expiredate )
-           ndays = (u16)((pk->expiredate - pk->timestamp) / 86400L);
-       else
-           ndays = 0;
-       write_16(a, ndays );
+  int rc = 0;
+  int n, i;
+  IOBUF a = iobuf_temp();
+  
+  if ( !pk->version )
+    iobuf_put( a, 3 );
+  else
+    iobuf_put( a, pk->version );
+  write_32(a, pk->timestamp );
+  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 )
+    write_fake_data( a, pk->pkey[0] );
+  for (i=0; i < n && !rc ; i++ )
+    rc = mpi_write(a, pk->pkey[i] );
+
+  if (!rc)
+    {
+      write_header2 (out, ctb, iobuf_get_temp_length(a), pk->hdrbytes);
+      rc = iobuf_write_temp ( out, a );
     }
     }
-    iobuf_put(a, pk->pubkey_algo );
-    n = pubkey_get_npkey( pk->pubkey_algo );
-    if( !n )
-       write_fake_data( a, pk->pkey[0] );
-    for(i=0; i < n; i++ )
-       mpi_write(a, pk->pkey[i] );
-
-    write_header2(out, ctb, iobuf_get_temp_length(a), pk->hdrbytes);
-    if( iobuf_write_temp( out, a ) )
-       rc = G10ERR_WRITE_FILE;
 
 
-    iobuf_close(a);
-    return rc;
+  iobuf_close(a);
+  return rc;
 }
 
 
 static int
 do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
 {
 }
 
 
 static int
 do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
 {
-    int rc = 0;
-    int i, nskey, npkey;
-    IOBUF a = iobuf_temp(); /* build in a self-enlarging buffer */
-
-    /* Write the version number - if none is specified, use 3 */
-    if( !sk->version )
-       iobuf_put( a, 3 );
-    else
-       iobuf_put( a, sk->version );
-    write_32(a, sk->timestamp );
-
-    /* v3  needs the expiration time */
-    if( sk->version < 4 ) {
-       u16 ndays;
-       if( sk->expiredate )
-           ndays = (u16)((sk->expiredate - sk->timestamp) / 86400L);
-       else
-           ndays = 0;
-       write_16(a, ndays);
-    }
-
-    iobuf_put(a, sk->pubkey_algo );
+  int rc = 0;
+  int i, nskey, npkey;
+  IOBUF a = iobuf_temp(); /* Build in a self-enlarging buffer.  */
 
 
-    /* get number of secret and public parameters.  They are held in
-       one array first the public ones, then the secret ones */
-    nskey = pubkey_get_nskey( sk->pubkey_algo );
-    npkey = pubkey_get_npkey( sk->pubkey_algo );
+  /* Write the version number - if none is specified, use 3 */
+  if ( !sk->version )
+    iobuf_put ( a, 3 );
+  else
+    iobuf_put ( a, sk->version );
+  write_32 (a, sk->timestamp );
 
 
-    /* If we don't have any public parameters - which is the case if
-       we don't know the algorithm used - the parameters are stored as
-       one blob in a faked (opaque) MPI */
-    if( !npkey ) {
-       write_fake_data( a, sk->skey[0] );
-       goto leave;
+  /* v3 needs the expiration time. */
+  if ( sk->version < 4 )
+    {
+      u16 ndays;
+      if ( sk->expiredate )
+        ndays = (u16)((sk->expiredate - sk->timestamp) / 86400L);
+      else
+        ndays = 0;
+      write_16(a, ndays);
+    }
+  
+  iobuf_put (a, sk->pubkey_algo );
+  
+  /* Get number of secret and public parameters.  They are held in one
+     array first the public ones, then the secret ones.  */
+  nskey = pubkey_get_nskey ( sk->pubkey_algo );
+  npkey = pubkey_get_npkey ( sk->pubkey_algo );
+  
+  /* If we don't have any public parameters - which is the case if we
+     don't know the algorithm used - the parameters are stored as one
+     blob in a faked (opaque) MPI. */
+  if ( !npkey ) 
+    {
+      write_fake_data( a, sk->skey[0] );
+      goto leave;
     }
     }
-    assert( npkey < nskey );
-
-    /* Writing the public parameters is easy */
-    for(i=0; i < npkey; i++ )
-       mpi_write(a, sk->skey[i] );
-
-    /* build the header for protected (encrypted) secret parameters */
-    if( sk->is_protected ) {
-       if( is_RSA(sk->pubkey_algo) && sk->version < 4
-                                   && !sk->protect.s2k.mode ) {
-            /* the simple rfc1991 (v3) way */
-           iobuf_put(a, sk->protect.algo );
-           iobuf_write(a, sk->protect.iv, sk->protect.ivlen );
+  assert ( npkey < nskey );
+
+  /* Writing the public parameters is easy. */
+  for (i=0; i < npkey; i++ )
+    if ((rc = mpi_write (a, sk->skey[i])))
+      goto leave;
+  
+  /* Build the header for protected (encrypted) secret parameters.  */
+  if ( sk->is_protected ) 
+    {
+      if ( is_RSA(sk->pubkey_algo) 
+           && sk->version < 4
+           && !sk->protect.s2k.mode )
+        {
+          /* The simple rfc1991 (v3) way. */
+          iobuf_put (a, sk->protect.algo );
+          iobuf_write (a, sk->protect.iv, sk->protect.ivlen );
        }
        }
-       else {
-          /* OpenPGP protection according to rfc2440 */
-           iobuf_put(a, sk->protect.sha1chk? 0xfe : 0xff );
-           iobuf_put(a, sk->protect.algo );
-           if( sk->protect.s2k.mode >= 1000 ) {
-                /* These modes are not possible in OpenPGP, we use them
-                   to implement our extensions, 101 can be seen as a
-                   private/experimental extension (this is not
-                   specified in rfc2440 but the same scheme is used
-                   for all other algorithm identifiers) */
-               iobuf_put(a, 101 ); 
-               iobuf_put(a, sk->protect.s2k.hash_algo );
-               iobuf_write(a, "GNU", 3 );
-               iobuf_put(a, sk->protect.s2k.mode - 1000 );
+      else
+        {
+          /* OpenPGP protection according to rfc2440. */
+          iobuf_put(a, sk->protect.sha1chk? 0xfe : 0xff );
+          iobuf_put(a, sk->protect.algo );
+          if ( sk->protect.s2k.mode >= 1000 )
+            {
+              /* These modes are not possible in OpenPGP, we use them
+                 to implement our extensions, 101 can be seen as a
+                 private/experimental extension (this is not specified
+                 in rfc2440 but the same scheme is used for all other
+                 algorithm identifiers) */
+              iobuf_put(a, 101 ); 
+              iobuf_put(a, sk->protect.s2k.hash_algo );
+              iobuf_write(a, "GNU", 3 );
+              iobuf_put(a, sk->protect.s2k.mode - 1000 );
            }
            }
-           else {
-               iobuf_put(a, sk->protect.s2k.mode );
-               iobuf_put(a, sk->protect.s2k.hash_algo );
+          else 
+            {
+              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 == 3 )
-               iobuf_write(a, sk->protect.s2k.salt, 8 );
-           if( sk->protect.s2k.mode == 3 )
-               iobuf_put(a, sk->protect.s2k.count ); 
-
-            /* For out special modes 1001, 1002 we do not need an IV */
-           if( sk->protect.s2k.mode != 1001 
-              && sk->protect.s2k.mode != 1002 )
-               iobuf_write(a, sk->protect.iv, sk->protect.ivlen );
+          if ( sk->protect.s2k.mode == 1
+               || sk->protect.s2k.mode == 3 )
+            iobuf_write (a, sk->protect.s2k.salt, 8 );
+
+          if ( sk->protect.s2k.mode == 3 )
+            iobuf_put (a, sk->protect.s2k.count ); 
+
+          /* For our special modes 1001, 1002 we do not need an IV. */
+          if ( sk->protect.s2k.mode != 1001 
+               && sk->protect.s2k.mode != 1002 )
+            iobuf_write (a, sk->protect.iv, sk->protect.ivlen );
        }
     }
        }
     }
-    else
-       iobuf_put(a, 0 );
-
-    if( sk->protect.s2k.mode == 1001 )
-        ; /* GnuPG extension - don't write a secret key at all */ 
-    else if( sk->protect.s2k.mode == 1002 )
-      {  /* GnuPG extension - divert to OpenPGP smartcard. */ 
-       iobuf_put(a, sk->protect.ivlen ); /* length of the serial
-                                             number or 0 for no serial
-                                             number. */
-        /* The serial number gets stored in the IV field. */
-        iobuf_write(a, sk->protect.iv, sk->protect.ivlen);
-      }
-    else if( sk->is_protected && sk->version >= 4 ) {
-        /* The secret key is protected - write it out as it is */
-       byte *p;
-       unsigned int ndata;
-
-       assert( mpi_is_opaque( sk->skey[npkey] ) );
-       p = mpi_get_opaque( sk->skey[npkey], &ndata );
-       iobuf_write(a, p, ndata );
+  else
+    iobuf_put (a, 0 );
+
+  if ( sk->protect.s2k.mode == 1001 )
+    ; /* GnuPG extension - don't write a secret key at all. */ 
+  else if ( sk->protect.s2k.mode == 1002 )
+    { 
+      /* GnuPG extension - divert to OpenPGP smartcard. */ 
+      iobuf_put(a, sk->protect.ivlen ); /* Length of the serial number
+                                           or 0 for no serial
+                                           number. */
+      /* The serial number gets stored in the IV field. */
+      iobuf_write(a, sk->protect.iv, sk->protect.ivlen);
+    }
+  else if ( sk->is_protected && sk->version >= 4 )
+    {
+      /* The secret key is protected - write it out as it is.  */
+      byte *p;
+      unsigned int ndatabits;
+      
+      assert (gcry_mpi_get_flag (sk->skey[npkey], GCRYMPI_FLAG_OPAQUE));
+      p = gcry_mpi_get_opaque (sk->skey[npkey], &ndatabits );
+      iobuf_write (a, p, (ndatabits+7)/8 );
     }
     }
-    else if( sk->is_protected ) {
-        /* The secret key is protected te old v4 way. */
-       for(   ; i < nskey; i++ ) {
-            byte *p;
-            unsigned int ndata;
-
-            assert (mpi_is_opaque (sk->skey[i]));
-            p = mpi_get_opaque (sk->skey[i], &ndata);
-            iobuf_write (a, p, ndata);
+  else if ( sk->is_protected ) 
+    {
+      /* The secret key is protected the old v4 way. */
+      for ( ; i < nskey; i++ ) 
+        {
+          byte *p;
+          unsigned int ndatabits;
+          
+          assert (gcry_mpi_get_flag (sk->skey[i], GCRYMPI_FLAG_OPAQUE));
+          p = gcry_mpi_get_opaque (sk->skey[i], &ndatabits);
+          iobuf_write (a, p, (ndatabits+7)/8);
         }
         }
-       write_16(a, sk->csum );
+      write_16(a, sk->csum );
     }
     }
-    else {
-        /* non-protected key */
-       for(   ; i < nskey; i++ )
-           mpi_write(a, sk->skey[i] );
-       write_16(a, sk->csum );
+  else
+    {
+      /* Non-protected key. */
+      for ( ; i < nskey; i++ )
+        if ( (rc = mpi_write (a, sk->skey[i])))
+          goto leave;
+      write_16 (a, sk->csum );
     }
 
     }
 
-  leave:
-    /* Build the header of the packet - which we must do after writing all
-       the other stuff, so that we know the length of the packet */
-    write_header2(out, ctb, iobuf_get_temp_length(a), sk->hdrbytes);
-    /* And finally write it out the real stream */
-    if( iobuf_write_temp( out, a ) )
-       rc = G10ERR_WRITE_FILE;
+ leave:
+  if (!rc)
+    {
+      /* Build the header of the packet - which we must do after
+         writing all the other stuff, so that we know the length of
+         the packet */
+      write_header2(out, ctb, iobuf_get_temp_length(a), sk->hdrbytes);
+      /* And finally write it out the real stream */
+      rc = iobuf_write_temp( out, a );
+    }
 
 
-    iobuf_close(a); /* close the remporary buffer */
-    return rc;
+  iobuf_close(a); /* Close the remporary buffer */
+  return rc;
 }
 
 static int
 }
 
 static int
@@ -410,8 +460,7 @@ do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc )
        iobuf_write(a, enc->seskey, enc->seskeylen );
 
     write_header(out, ctb, iobuf_get_temp_length(a) );
        iobuf_write(a, enc->seskey, enc->seskeylen );
 
     write_header(out, ctb, iobuf_get_temp_length(a) );
-    if( iobuf_write_temp( out, a ) )
-       rc = G10ERR_WRITE_FILE;
+    rc = iobuf_write_temp( out, a );
 
     iobuf_close(a);
     return rc;
 
     iobuf_close(a);
     return rc;
@@ -421,32 +470,35 @@ do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc )
 static int
 do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
 {
 static int
 do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
 {
-    int rc = 0;
-    int n, i;
-    IOBUF a = iobuf_temp();
-
-    write_version( a, ctb );
-    if( enc->throw_keyid ) {
-       write_32(a, 0 );  /* don't tell Eve who can decrypt the message */
-       write_32(a, 0 );
+  int rc = 0;
+  int n, i;
+  IOBUF a = iobuf_temp();
+  
+  write_version( a, ctb );
+  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] );
+  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 )
-       write_fake_data( a, enc->data[0] );
-    for(i=0; i < n; i++ )
-       mpi_write(a, enc->data[i] );
-
-    write_header(out, ctb, iobuf_get_temp_length(a) );
-    if( iobuf_write_temp( out, a ) )
-       rc = G10ERR_WRITE_FILE;
-
-    iobuf_close(a);
-    return rc;
+  iobuf_put(a,enc->pubkey_algo );
+  n = pubkey_get_nenc( enc->pubkey_algo );
+  if ( !n )
+    write_fake_data( a, enc->data[0] );
+  for (i=0; i < n && !rc ; i++ )
+    rc = mpi_write(a, enc->data[i] );
+
+  if (!rc)
+    {
+      write_header(out, ctb, iobuf_get_temp_length(a) );
+      rc = iobuf_write_temp( out, a );
+    }
+  iobuf_close(a);
+  return rc;
 }
 
 
 }
 
 
@@ -476,16 +528,16 @@ do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt )
     iobuf_put(out, pt->namelen );
     for(i=0; i < pt->namelen; i++ )
        iobuf_put(out, pt->name[i] );
     iobuf_put(out, pt->namelen );
     for(i=0; i < pt->namelen; i++ )
        iobuf_put(out, pt->name[i] );
-    if( write_32(out, pt->timestamp ) )
-       rc = G10ERR_WRITE_FILE;
+    rc = write_32(out, pt->timestamp );
+    if (rc) 
+      return rc;
 
     n = 0;
     while( (nbytes=iobuf_read(pt->buf, buf, 1000)) != -1 ) {
 
     n = 0;
     while( (nbytes=iobuf_read(pt->buf, buf, 1000)) != -1 ) {
-       if( iobuf_write(out, buf, nbytes) == -1 ) {
-           rc = G10ERR_WRITE_FILE;
-           break;
-       }
-       n += nbytes;
+      rc = iobuf_write (out, buf, nbytes);
+      if (rc)
+        break;
+      n += nbytes;
     }
     wipememory(buf,1000); /* burn the buffer */
     if( (ctb&0x40) && !pt->len )
     }
     wipememory(buf,1000); /* burn the buffer */
     if( (ctb&0x40) && !pt->len )
@@ -537,7 +589,7 @@ do_compressed( IOBUF out, int ctb, PKT_compressed *cd )
 {
     int rc = 0;
 
 {
     int rc = 0;
 
-    /* We must use the old convention and don't use blockmode for tyhe
+    /* We must use the old convention and don't use blockmode for the
        sake of PGP 2 compatibility.  However if the new_ctb flag was
        set, CTB is already formatted as new style and write_header2
        does create a partial length encoding using new the new
        sake of PGP 2 compatibility.  However if the new_ctb flag was
        set, CTB is already formatted as new style and write_header2
        does create a partial length encoding using new the new
@@ -748,12 +800,12 @@ build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
         /*log_debug ("updating area for type %d\n", type );*/
     }
     else if (oldarea) {
         /*log_debug ("updating area for type %d\n", type );*/
     }
     else if (oldarea) {
-        newarea = m_realloc (oldarea, sizeof (*newarea) + n - 1);
+        newarea = xrealloc (oldarea, sizeof (*newarea) + n - 1);
         newarea->size = n;
         /*log_debug ("reallocating area for type %d\n", type );*/
     }
     else {
         newarea->size = n;
         /*log_debug ("reallocating area for type %d\n", type );*/
     }
     else {
-        newarea = m_alloc (sizeof (*newarea) + n - 1);
+        newarea = xmalloc (sizeof (*newarea) + n - 1);
         newarea->size = n;
         /*log_debug ("allocating area for type %d\n", type );*/
     }
         newarea->size = n;
         /*log_debug ("allocating area for type %d\n", type );*/
     }
@@ -821,7 +873,8 @@ build_sig_subpkt_from_sig( PKT_signature *sig )
        if(sig->expiredate>sig->timestamp)
          u=sig->expiredate-sig->timestamp;
        else
        if(sig->expiredate>sig->timestamp)
          u=sig->expiredate-sig->timestamp;
        else
-         u=0;
+         u=1; /* A 1-second expiration time is the shortest one
+                 OpenPGP has */
 
        buf[0] = (u >> 24) & 0xff;
        buf[1] = (u >> 16) & 0xff;
 
        buf[0] = (u >> 24) & 0xff;
        buf[1] = (u >> 16) & 0xff;
@@ -854,7 +907,7 @@ build_attribute_subpkt(PKT_user_id *uid,byte type,
 
   /* realloc uid->attrib_data to the right size */
 
 
   /* realloc uid->attrib_data to the right size */
 
-  uid->attrib_data=m_realloc(uid->attrib_data,
+  uid->attrib_data=xrealloc(uid->attrib_data,
                             uid->attrib_len+idx+1+headerlen+buflen);
 
   attrib=&uid->attrib_data[uid->attrib_len];
                             uid->attrib_len+idx+1+headerlen+buflen);
 
   attrib=&uid->attrib_data[uid->attrib_len];
@@ -885,58 +938,229 @@ build_attribute_subpkt(PKT_user_id *uid,byte type,
   uid->attrib_len+=idx+headerlen+buflen;
 }
 
   uid->attrib_len+=idx+headerlen+buflen;
 }
 
+struct notation *
+string_to_notation(const char *string,int is_utf8)
+{
+  const char *s;
+  int saw_at=0;
+  struct notation *notation;
+
+  notation=xmalloc_clear(sizeof(*notation));
+
+  if(*string=='-')
+    {
+      notation->flags.ignore=1;
+      string++;
+    }
+
+  if(*string=='!')
+    {
+      notation->flags.critical=1;
+      string++;
+    }
+
+  /* If and when the IETF assigns some official name tags, we'll have
+     to add them here. */
+
+  for( s=string ; *s != '='; s++ )
+    {
+      if( *s=='@')
+       saw_at++;
+
+      /* -notationname is legal without an = sign */
+      if(!*s && notation->flags.ignore)
+       break;
+
+      if( !*s || !isascii (*s) || (!isgraph(*s) && !isspace(*s)) )
+       {
+         log_error(_("a notation name must have only printable characters"
+                     " or spaces, and end with an '='\n") );
+         goto fail;
+       }
+    }
+
+  notation->name=xmalloc((s-string)+1);
+  strncpy(notation->name,string,s-string);
+  notation->name[s-string]='\0';
+
+  if(!saw_at && !opt.expert)
+    {
+      log_error(_("a user notation name must contain the '@' character\n"));
+      goto fail;
+    }
+
+  if (saw_at > 1)
+    {
+      log_error(_("a notation name must not contain more than"
+                 " one '@' character\n"));
+      goto fail;
+    }
+
+  if(*s)
+    {
+      const char *i=s+1;
+      int highbit=0;
+
+      /* we only support printable text - therefore we enforce the use
+        of only printable characters (an empty value is valid) */
+      for(s++; *s ; s++ )
+       {
+         if ( !isascii (*s) )
+           highbit=1;
+         else if (iscntrl(*s))
+           {
+             log_error(_("a notation value must not use any"
+                         " control characters\n"));
+             goto fail;
+           }
+       }
+
+      if(!highbit || is_utf8)
+       notation->value=xstrdup(i);
+      else
+       notation->value=native_to_utf8(i);
+    }
+
+  return notation;
+
+ fail:
+  free_notation(notation);
+  return NULL;
+}
+
+struct notation *
+sig_to_notation(PKT_signature *sig)
+{
+  const byte *p;
+  size_t len;
+  int seq=0,crit;
+  struct notation *list=NULL;
+
+  while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,&len,&seq,&crit)))
+    {
+      int n1,n2;
+      struct notation *n=NULL;
+
+      if(len<8)
+       {
+         log_info(_("WARNING: invalid notation data found\n"));
+         continue;
+       }
+
+      n1=(p[4]<<8)|p[5];
+      n2=(p[6]<<8)|p[7];
+
+      if(8+n1+n2!=len)
+       {
+         log_info(_("WARNING: invalid notation data found\n"));
+         continue;
+       }
+
+      n=xmalloc_clear(sizeof(*n));
+      n->name=xmalloc(n1+1);
+
+      memcpy(n->name,&p[8],n1);
+      n->name[n1]='\0';
+
+      if(p[0]&0x80)
+       {
+         n->value=xmalloc(n2+1);
+         memcpy(n->value,&p[8+n1],n2);
+         n->value[n2]='\0';
+       }
+      else
+       {
+         n->bdat=xmalloc(n2);
+         n->blen=n2;
+         memcpy(n->bdat,&p[8+n1],n2);
+
+         n->value=xmalloc(2+strlen(_("not human readable"))+2+1);
+         strcpy(n->value,"[ ");
+         strcat(n->value,_("not human readable"));
+         strcat(n->value," ]");
+       }
+
+      n->flags.critical=crit;
+
+      n->next=list;
+      list=n;
+    }
+
+  return list;
+}
+
+void
+free_notation(struct notation *notation)
+{
+  while(notation)
+    {
+      struct notation *n=notation;
+
+      xfree(n->name);
+      xfree(n->value);
+      xfree(n->altvalue);
+      xfree(n->bdat);
+      notation=n->next;
+      xfree(n);
+    }
+}
+
 static int
 do_signature( IOBUF out, int ctb, PKT_signature *sig )
 {
 static int
 do_signature( IOBUF out, int ctb, PKT_signature *sig )
 {
-    int rc = 0;
-    int n, i;
-    IOBUF a = iobuf_temp();
+  int rc = 0;
+  int n, i;
+  IOBUF a = iobuf_temp();
 
 
-    if( !sig->version )
-       iobuf_put( a, 3 );
-    else
-       iobuf_put( a, sig->version );
-    if( sig->version < 4 )
-       iobuf_put(a, 5 ); /* constant */
-    iobuf_put(a, sig->sig_class );
-    if( sig->version < 4 ) {
-       write_32(a, sig->timestamp );
-       write_32(a, sig->keyid[0] );
-       write_32(a, sig->keyid[1] );
+  if ( !sig->version )
+    iobuf_put( a, 3 );
+  else
+    iobuf_put( a, sig->version );
+  if ( sig->version < 4 )
+    iobuf_put (a, 5 ); /* Constant */
+  iobuf_put (a, sig->sig_class );
+  if ( sig->version < 4 ) 
+    {
+      write_32(a, sig->timestamp );
+      write_32(a, sig->keyid[0] );
+      write_32(a, sig->keyid[1] );
     }
     }
-    iobuf_put(a, sig->pubkey_algo );
-    iobuf_put(a, sig->digest_algo );
-    if( sig->version >= 4 ) {
-       size_t nn;
-       /* timestamp and keyid must have been packed into the
-        * subpackets prior to the call of this function, because
-        * these subpackets are hashed */
-       nn = sig->hashed? sig->hashed->len : 0;
-       write_16(a, nn);
-       if( nn )
-           iobuf_write( a, sig->hashed->data, nn );
-       nn = sig->unhashed? sig->unhashed->len : 0;
-       write_16(a, nn);
-       if( nn )
-           iobuf_write( a, sig->unhashed->data, nn );
+  iobuf_put(a, sig->pubkey_algo );
+  iobuf_put(a, sig->digest_algo );
+  if ( sig->version >= 4 ) 
+    {
+      size_t nn;
+      /* Timestamp and keyid must have been packed into the subpackets
+        prior to the call of this function, because these subpackets
+        are hashed. */
+      nn = sig->hashed? sig->hashed->len : 0;
+      write_16(a, nn);
+      if (nn)
+        iobuf_write( a, sig->hashed->data, nn );
+      nn = sig->unhashed? sig->unhashed->len : 0;
+      write_16(a, nn);
+      if (nn)
+        iobuf_write( a, sig->unhashed->data, nn );
+    }
+  iobuf_put(a, sig->digest_start[0] );
+  iobuf_put(a, sig->digest_start[1] );
+  n = pubkey_get_nsig( sig->pubkey_algo );
+  if ( !n )
+    write_fake_data( a, sig->data[0] );
+  for (i=0; i < n && !rc ; i++ )
+    rc = mpi_write(a, sig->data[i] );
+
+  if (!rc)
+    {
+      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) );
+      rc = iobuf_write_temp( out, a );
     }
     }
-    iobuf_put(a, sig->digest_start[0] );
-    iobuf_put(a, sig->digest_start[1] );
-    n = pubkey_get_nsig( sig->pubkey_algo );
-    if( !n )
-       write_fake_data( a, sig->data[0] );
-    for(i=0; i < n; i++ )
-       mpi_write(a, sig->data[i] );
-
-    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;
 
 
-    iobuf_close(a);
-    return rc;
+  iobuf_close(a);
+  return rc;
 }
 
 
 }
 
 
@@ -955,8 +1179,7 @@ do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops )
     iobuf_put(a, ops->last );
 
     write_header(out, ctb, iobuf_get_temp_length(a) );
     iobuf_put(a, ops->last );
 
     write_header(out, ctb, iobuf_get_temp_length(a) );
-    if( iobuf_write_temp( out, a ) )
-       rc = G10ERR_WRITE_FILE;
+    rc = iobuf_write_temp( out, a );
 
     iobuf_close(a);
     return rc;
 
     iobuf_close(a);
     return rc;
@@ -978,9 +1201,7 @@ write_32(IOBUF out, u32 a)
     iobuf_put(out, a>> 24);
     iobuf_put(out, a>> 16);
     iobuf_put(out, a>> 8);
     iobuf_put(out, a>> 24);
     iobuf_put(out, a>> 16);
     iobuf_put(out, a>> 8);
-    if( iobuf_put(out, a) )
-       return -1;
-    return 0;
+    return iobuf_put(out, a);
 }
 
 
 }
 
 
@@ -1020,14 +1241,16 @@ write_header( IOBUF out, int ctb, u32 len )
 
 
 static int
 
 
 static int
-write_sign_packet_header( IOBUF out, int ctb, u32 len )
+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;
+  (void)ctb;
+
+  /* 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;
 }
 
 /****************
 }
 
 /****************
@@ -1129,9 +1352,11 @@ write_new_header( IOBUF out, int ctb, u32 len, int hdrlen )
 }
 
 static int
 }
 
 static int
-write_version( IOBUF out, int ctb )
+write_version (IOBUF out, int ctb)
 {
 {
-    if( iobuf_put( out, 3 ) )
-       return -1;
-    return 0;
+  (void)ctb;
+
+  if (iobuf_put (out, 3))
+    return -1;
+  return 0;
 }
 }