Renamed the lock functions.
[gnupg.git] / g10 / build-packet.c
index 88f196a..159b783 100644 (file)
@@ -1,6 +1,6 @@
 /* build-packet.c - assemble packets and write them
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- *               2006 Free Software Foundation, Inc.
+ *               2006, 2010, 2011  Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <ctype.h>
 
 #include "gpg.h"
+#include "util.h"
 #include "packet.h"
 #include "status.h"
 #include "iobuf.h"
-#include "util.h"
 #include "cipher.h"
 #include "i18n.h"
 #include "options.h"
 
 static int 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_secret_key( IOBUF out, int ctb, PKT_secret_key *pk );
+static int do_key (iobuf_t out, int ctb, PKT_public_key *pk);
 static int 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 u32 calc_plaintext( PKT_plaintext *pt );
@@ -72,8 +71,16 @@ build_packet( IOBUF out, PACKET *pkt )
        log_debug("build_packet() type=%d\n", pkt->pkttype );
     assert( pkt->pkt.generic );
 
-    switch( (pkttype = pkt->pkttype) )
+    switch ((pkttype = pkt->pkttype))
       {
+      case PKT_PUBLIC_KEY:
+        if (pkt->pkt.public_key->seckey_info)
+          pkttype = PKT_SECRET_KEY;
+        break;
+      case PKT_PUBLIC_SUBKEY:
+        if (pkt->pkt.public_key->seckey_info)
+          pkttype = PKT_SECRET_SUBKEY;
+        break;
       case PKT_PLAINTEXT: new_ctb = pkt->pkt.plaintext->new_ctb; break;
       case PKT_ENCRYPTED:
       case PKT_ENCRYPTED_MDC: new_ctb = pkt->pkt.encrypted->new_ctb; break;
@@ -107,11 +114,9 @@ build_packet( IOBUF out, PACKET *pkt )
        break;
       case PKT_PUBLIC_SUBKEY:
       case PKT_PUBLIC_KEY:
-       rc = do_public_key( out, ctb, pkt->pkt.public_key );
-       break;
       case PKT_SECRET_SUBKEY:
       case PKT_SECRET_KEY:
-       rc = do_secret_key( out, ctb, pkt->pkt.secret_key );
+       rc = do_key (out, ctb, pkt->pkt.public_key);
        break;
       case PKT_SYMKEY_ENC:
        rc = do_symkey_enc( out, ctb, pkt->pkt.symkey_enc );
@@ -152,32 +157,41 @@ build_packet( IOBUF out, PACKET *pkt )
 /*
  * Write the mpi A to OUT.
  */
-static int
-mpi_write (iobuf_t out, gcry_mpi_t a)
+gpg_error_t
+gpg_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 )
+  if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
     {
-      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);
+      unsigned int nbits;
+      const void *p;
+
+      p = gcry_mpi_get_opaque (a, &nbits);
+      rc = iobuf_write (out, p, (nbits+7)/8);
+    }
+  else
+    {
+      char buffer[(MAX_EXTERN_MPI_BITS+7)/8+2]; /* 2 is for the mpi length. */
+      size_t nbytes;
+
+      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.  */
 u32
 calc_packet_length( PACKET *pkt )
 {
@@ -211,229 +225,197 @@ calc_packet_length( PACKET *pkt )
     return n;
 }
 
-static void
-write_fake_data (IOBUF out, gcry_mpi_t a)
-{
-  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 gpg_error_t
+write_fake_data (IOBUF out, gcry_mpi_t a)
 {
-    int rc;
+  unsigned int n;
+  void *p;
 
-    if( uid->attrib_data )
-      {
-       write_header(out, ctb, uid->attrib_len);
-       rc = iobuf_write( out, uid->attrib_data, uid->attrib_len );
-      }
-    else
-      {
-        write_header2( out, ctb, uid->len, 2 );
-       rc = iobuf_write( out, uid->name, uid->len );
-      }
+  if (!a)
     return 0;
+  p = gcry_mpi_get_opaque ( a, &n);
+  return iobuf_write (out, p, (n+7)/8 );
 }
 
+
 static int
-do_public_key( IOBUF out, int ctb, PKT_public_key *pk )
+do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
 {
-  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 ) 
+  int rc;
+
+  if (uid->attrib_data)
     {
-      u16 ndays;
-      if ( pk->expiredate )
-        ndays = (u16)((pk->expiredate - pk->timestamp) / 86400L);
-      else
-        ndays = 0;
-      write_16(a, ndays );
+      write_header(out, ctb, uid->attrib_len);
+      rc = iobuf_write( out, uid->attrib_data, uid->attrib_len );
     }
-  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)
+  else
     {
-      write_header2 (out, ctb, iobuf_get_temp_length(a), pk->hdrbytes);
-      rc = iobuf_write_temp ( out, a );
+      write_header2( out, ctb, uid->len, 2 );
+      rc = iobuf_write( out, uid->name, uid->len );
     }
-
-  iobuf_close(a);
   return rc;
 }
 
 
 static int
-do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
+do_key (iobuf_t out, int ctb, PKT_public_key *pk)
 {
-  int rc = 0;
+  gpg_error_t err = 0;
   int i, nskey, npkey;
-  IOBUF a = iobuf_temp(); /* Build in a self-enlarging buffer.  */
+  iobuf_t a = iobuf_temp(); /* Build in a self-enlarging buffer.  */
 
   /* Write the version number - if none is specified, use 3 */
-  if ( !sk->version )
+  if ( !pk->version )
     iobuf_put ( a, 3 );
   else
-    iobuf_put ( a, sk->version );
-  write_32 (a, sk->timestamp );
+    iobuf_put ( a, pk->version );
+  write_32 (a, pk->timestamp );
 
   /* v3 needs the expiration time. */
-  if ( sk->version < 4 )
+  if ( pk->version < 4 )
     {
       u16 ndays;
-      if ( sk->expiredate )
-        ndays = (u16)((sk->expiredate - sk->timestamp) / 86400L);
+      if ( pk->expiredate )
+        ndays = (u16)((pk->expiredate - pk->timestamp) / 86400L);
       else
         ndays = 0;
       write_16(a, ndays);
     }
-  
-  iobuf_put (a, sk->pubkey_algo );
-  
+
+  iobuf_put (a, pk->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 );
-  
+  nskey = pubkey_get_nskey (pk->pubkey_algo);
+  npkey = pubkey_get_npkey (pk->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 ) 
+  if (!npkey)
     {
-      write_fake_data( a, sk->skey[0] );
+      write_fake_data (a, pk->pkey[0]);
       goto leave;
     }
-  assert ( npkey < nskey );
+  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
+      err = gpg_mpi_write (a, pk->pkey[i]);
+      if (err)
+        goto leave;
+    }
+
+
+  if (pk->seckey_info)
+    {
+      /* This is a secret key packet.  */
+      struct seckey_info *ski = pk->seckey_info;
+
+      /* Build the header for protected (encrypted) secret parameters.  */
+      if (ski->is_protected)
         {
-          /* 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 )
+          if ( is_RSA (pk->pubkey_algo) && pk->version < 4 && !ski->s2k.mode )
             {
-              /* 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 
+              /* The simple rfc1991 (v3) way. */
+              iobuf_put (a, ski->algo );
+              iobuf_write (a, ski->iv, ski->ivlen);
+            }
+          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 ); 
+              /* OpenPGP protection according to rfc2440. */
+              iobuf_put (a, ski->sha1chk? 0xfe : 0xff);
+              iobuf_put (a, ski->algo);
+              if (ski->s2k.mode >= 1000)
+                {
+                  /* These modes are not possible in OpenPGP, we use
+                     them to implement our extensions, 101 can be
+                     viewed 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, ski->s2k.hash_algo);
+                  iobuf_write (a, "GNU", 3 );
+                  iobuf_put (a, ski->s2k.mode - 1000);
+                }
+              else
+                {
+                  iobuf_put (a, ski->s2k.mode);
+                  iobuf_put (a, ski->s2k.hash_algo);
+                }
+
+              if (ski->s2k.mode == 1 || ski->s2k.mode == 3)
+                iobuf_write (a, ski->s2k.salt, 8);
+
+              if (ski->s2k.mode == 3)
+                iobuf_put (a, ski->s2k.count);
+
+              /* For our special modes 1001, 1002 we do not need an IV. */
+              if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002)
+                iobuf_write (a, ski->iv, ski->ivlen);
+            }
+        }
+      else /* Not protected. */
+        iobuf_put (a, 0 );
 
-          /* 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 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 the old v4 way. */
-      for ( ; i < nskey; i++ ) 
+      if (ski->s2k.mode == 1001)
+        ; /* GnuPG extension - don't write a secret key at all. */
+      else if (ski->s2k.mode == 1002)
         {
+          /* GnuPG extension - divert to OpenPGP smartcard. */
+          /* Length of the serial number or 0 for no serial number. */
+          iobuf_put (a, ski->ivlen );
+          /* The serial number gets stored in the IV field.  */
+          iobuf_write (a, ski->iv, ski->ivlen);
+        }
+      else if (ski->is_protected && pk->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[i], GCRYMPI_FLAG_OPAQUE));
-          p = gcry_mpi_get_opaque (sk->skey[i], &ndatabits);
-          iobuf_write (a, p, (ndatabits+7)/8);
+
+          assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE));
+          p = gcry_mpi_get_opaque (pk->pkey[npkey], &ndatabits);
+          iobuf_write (a, p, (ndatabits+7)/8 );
+        }
+      else if (ski->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 (pk->pkey[i], GCRYMPI_FLAG_OPAQUE));
+              p = gcry_mpi_get_opaque (pk->pkey[i], &ndatabits);
+              iobuf_write (a, p, (ndatabits+7)/8);
+            }
+          write_16 (a, ski->csum );
+        }
+      else
+        {
+          /* Non-protected key. */
+          for ( ; i < nskey; i++ )
+            if ( (err = gpg_mpi_write (a, pk->pkey[i])))
+              goto leave;
+          write_16 (a, ski->csum );
         }
-      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:
-  if (!rc)
+  if (!err)
     {
       /* 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 );
+      write_header2 (out, ctb, iobuf_get_temp_length(a), pk->hdrbytes);
+      /* And finally write it out to the real stream. */
+      err = iobuf_write_temp (out, a);
     }
 
-  iobuf_close(a); /* Close the remporary buffer */
-  return rc;
+  iobuf_close (a); /* Close the temporary buffer */
+  return err;
 }
 
 static int
@@ -473,9 +455,9 @@ 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 ) 
+  if ( enc->throw_keyid )
     {
       write_32(a, 0 );  /* Don't tell Eve who can decrypt the message.  */
       write_32(a, 0 );
@@ -489,13 +471,14 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
   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] );
+    rc = gpg_mpi_write (a, enc->data[i]);
 
   if (!rc)
     {
-      write_header(out, ctb, iobuf_get_temp_length(a) );
-      rc = iobuf_write_temp( out, a );
+      write_header (out, ctb, iobuf_get_temp_length(a) );
+      rc = iobuf_write_temp (out, a);
     }
   iobuf_close(a);
   return rc;
@@ -529,7 +512,7 @@ do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt )
     for(i=0; i < pt->namelen; i++ )
        iobuf_put(out, pt->name[i] );
     rc = write_32(out, pt->timestamp );
-    if (rc) 
+    if (rc)
       return rc;
 
     n = 0;
@@ -589,7 +572,7 @@ do_compressed( IOBUF out, int ctb, PKT_compressed *cd )
 {
     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
@@ -645,7 +628,7 @@ delete_sig_subpkt (subpktarea_t *area, sigsubpkttype_t reqtype )
        }
        if( buflen < n )
            break;
-        
+
        type = *buffer & 0x7f;
        if( type == reqtype ) {
            buffer++;
@@ -679,7 +662,7 @@ delete_sig_subpkt (subpktarea_t *area, sigsubpkttype_t reqtype )
  * Note: All pointers into sig->[un]hashed (e.g. returned by
  * parse_sig_subpkt) are not valid after a call to this function.  The
  * data to put into the subpaket should be in a buffer with a length
- * of buflen. 
+ * of buflen.
  */
 void
 build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
@@ -782,7 +765,7 @@ build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
       case SIGSUBPKT_SIGNATURE:
         hashed = 0;
         break;
-      default: 
+      default:
         hashed = 1;
         break;
       }
@@ -833,7 +816,7 @@ build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
        memcpy (p, buffer, buflen);
     }
 
-    if (hashed) 
+    if (hashed)
        sig->hashed = newarea;
     else
        sig->unhashed = newarea;
@@ -1119,7 +1102,7 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
   if ( sig->version < 4 )
     iobuf_put (a, 5 ); /* Constant */
   iobuf_put (a, sig->sig_class );
-  if ( sig->version < 4 ) 
+  if ( sig->version < 4 )
     {
       write_32(a, sig->timestamp );
       write_32(a, sig->keyid[0] );
@@ -1127,7 +1110,7 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
     }
   iobuf_put(a, sig->pubkey_algo );
   iobuf_put(a, sig->digest_algo );
-  if ( sig->version >= 4 ) 
+  if ( sig->version >= 4 )
     {
       size_t nn;
       /* Timestamp and keyid must have been packed into the subpackets
@@ -1148,7 +1131,7 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
   if ( !n )
     write_fake_data( a, sig->data[0] );
   for (i=0; i < n && !rc ; i++ )
-    rc = mpi_write(a, sig->data[i] );
+    rc = gpg_mpi_write (a, sig->data[i] );
 
   if (!rc)
     {
@@ -1241,14 +1224,16 @@ write_header( IOBUF out, int ctb, u32 len )
 
 
 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;
 }
 
 /****************
@@ -1350,9 +1335,11 @@ write_new_header( IOBUF out, int ctb, u32 len, int hdrlen )
 }
 
 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;
 }