Reworked the ECC changes to better fit into the Libgcrypt API.
[gnupg.git] / g10 / parse-packet.c
index d43ab2c..83be15d 100644 (file)
@@ -741,6 +741,61 @@ read_rest (IOBUF inp, size_t pktlen, int partial)
 }
 
 
+/* Read a special size+body from INP.  On success store an opaque MPI
+   with it at R_DATA.  On error return an error code and store NULL at
+   R_DATA.  Even in the error case store the number of read bytes at
+   R_NREAD.  The caller shall pass the remaining size of the packet in
+   PKTLEN.  */
+static gpg_error_t
+read_size_body (iobuf_t inp, int pktlen, size_t *r_nread,
+                gcry_mpi_t *r_data)
+{
+  char buffer[256];
+  char *tmpbuf;
+  int i, c, nbytes;
+
+  *r_nread = 0;
+  *r_data = NULL;
+
+  if (!pktlen)
+    return gpg_error (GPG_ERR_INV_PACKET);
+  c = iobuf_readbyte (inp);
+  if (c < 0)
+    return gpg_error (GPG_ERR_INV_PACKET);
+  pktlen--;
+  ++*r_nread;
+  nbytes = c;
+  if (nbytes < 2 || nbytes > 254)
+    return gpg_error (GPG_ERR_INV_PACKET);
+  if (nbytes > pktlen)
+    return gpg_error (GPG_ERR_INV_PACKET);
+
+  buffer[0] = nbytes;
+
+  for (i = 0; i < nbytes; i++)
+    {
+      c = iobuf_get (inp);
+      if (c < 0)
+        return gpg_error (GPG_ERR_INV_PACKET);
+      ++*r_nread;
+      buffer[1+i] = c;
+    }
+
+  tmpbuf = xtrymalloc (1 + nbytes);
+  if (!tmpbuf)
+    return gpg_error_from_syserror ();
+  memcpy (tmpbuf, buffer, 1 + nbytes);
+  *r_data = gcry_mpi_set_opaque (NULL, tmpbuf, 8 * (1 + nbytes));
+  if (!*r_data)
+    {
+      xfree (tmpbuf);
+      return gpg_error_from_syserror ();
+    }
+  return 0;
+}
+
+
+/* Parse a marker packet.  */
 static int
 parse_marker (IOBUF inp, int pkttype, unsigned long pktlen)
 {
@@ -939,40 +994,30 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
     }
   else
     {
-      if( k->pubkey_algo != PUBKEY_ALGO_ECDH )  {
-        for (i = 0; i < ndata; i++)
-         {
-           n = pktlen;
-           k->data[i] = mpi_read (inp, &n, 0);
-           pktlen -= n;
-           if (list_mode)
-             {
-               es_fprintf (listfp, "\tdata: ");
-               mpi_print (listfp, k->data[i], mpi_print_mode);
-               es_putc ('\n', listfp);
-             }
-           if (!k->data[i])
-             rc = gpg_error (GPG_ERR_INV_PACKET);
-         }
-      }
-      else  
+      for (i = 0; i < ndata; i++)
         {
-               byte encr_buf[255];
-               assert( ndata == 2 );
-               n = pktlen; k->data[0] = mpi_read(inp, &n, 0); pktlen -=n;
-               rc = iobuf_read_size_body( inp, encr_buf, sizeof(encr_buf), pktlen, k->data+1 );
-               if( rc )
-                       goto leave;
-               if( list_mode ) {
-                       es_fprintf (listfp, "\tdata: ");
-                       mpi_print(listfp, k->data[0], mpi_print_mode );
-                       es_putc ('\n', listfp);
-                       es_fprintf (listfp, "\tdata: [% 3d bytes] ", encr_buf[0]+1);
-                       mpi_print(listfp, k->data[1], mpi_print_mode );
-                       es_putc ('\n', listfp);
-               }
-               pktlen -= (encr_buf[0]+1);
-      }
+          if (k->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
+            {
+              rc = read_size_body (inp, pktlen, &n, k->data+i);
+              pktlen -= n;
+            }
+          else
+            {
+              n = pktlen;
+              k->data[i] = mpi_read (inp, &n, 0);
+              pktlen -= n;
+              if (!k->data[i])
+                rc = gpg_error (GPG_ERR_INV_PACKET);
+            }
+          if (rc)
+            goto leave;
+          if (list_mode)
+            {
+              es_fprintf (listfp, "\tdata: ");
+              mpi_print (listfp, k->data[i], mpi_print_mode);
+              es_putc ('\n', listfp);
+            }
+        }
     }
 
  leave:
@@ -1933,7 +1978,6 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
       unknown_pubkey_warning (algorithm);
     }
 
-
   if (!npkey)
     {
       /* Unknown algorithm - put data into an opaque MPI.  */
@@ -1945,66 +1989,32 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
     }
   else
     {
-      /* Fill in public key parameters.  */
-      if( algorithm != PUBKEY_ALGO_ECDSA && algorithm != PUBKEY_ALGO_ECDH )  {
-        for (i = 0; i < npkey; i++)
-         {
-           n = pktlen;
-           pk->pkey[i] = mpi_read (inp, &n, 0);
-           pktlen -= n;
-           if (list_mode)
-             {
-               es_fprintf (listfp, "\tpkey[%d]: ", i);
-               mpi_print (listfp, pk->pkey[i], mpi_print_mode);
-               es_putc ('\n', listfp);
-             }
-           if (!pk->pkey[i])
-             err = gpg_error (GPG_ERR_INV_PACKET);
-         }
-      }
-      else  {
-            /* note that the code in this function ignores the errors */
-           byte name_oid[256];
-           err = iobuf_read_size_body( inp, name_oid, sizeof(name_oid), pktlen, pk->pkey+0 );
-           if( err )
-               goto leave;
-           n = name_oid[0];
-           if( list_mode )
-              es_fprintf (listfp,   "\tpkey[0]: curve OID [%d] ...%02x %02x\n", 
-                       n, name_oid[1+n-2], name_oid[1+n-1] );
-           pktlen -= (n+1);
-           /* set item [1], which corresponds to the public key; these two fields are all we need to uniquely define the key */
-           // log_debug("Parsing ecc public key in the public packet, pktlen=%lu\n", pktlen);
-           n = pktlen; pk->pkey[1] = mpi_read( inp, &n, 0 ); pktlen -=n;
-           if( pk->pkey[1]==NULL )
-               err = gpg_error(G10ERR_INVALID_PACKET);
-           else if( list_mode ) {
-               es_fprintf (listfp,   "\tpkey[1]: ");
-               mpi_print(listfp, pk->pkey[1], mpi_print_mode);
-               es_putc ('\n', listfp);
-           }
-           /* One more field for ECDH */
-           if( algorithm == PUBKEY_ALGO_ECDH )  {
-#define kek_params name_oid
-              err = iobuf_read_size_body( inp, kek_params, sizeof(kek_params), pktlen, pk->pkey+2 );
-              if( err )
-                goto leave;
-              n = kek_params[0];
-              if( kek_params[1] != 1 ) {
-                       log_error("invalid ecdh KEK parameters field type in private key: understand type 1, but found 0x%02x\n", kek_params[1]);
-                       err = gpg_error(G10ERR_INVALID_PACKET);
-                       goto leave;
-              }
-              if( list_mode )
-                es_fprintf (listfp,   "\tpkey[2]: KEK params type=01 hash:%d sym-algo:%d\n", kek_params[1+n-2], kek_params[1+n-1] );
-              pktlen -= (n+1);
-#undef kek_params
-           }
-     }
-      if (err)
-       goto leave;
+      for (i = 0; i < npkey; i++)
+        {
+          if ((algorithm == PUBKEY_ALGO_ECDSA
+               || algorithm == PUBKEY_ALGO_ECDH) && (i==0 || i == 2))
+            {
+              err = read_size_body (inp, pktlen, &n, pk->pkey+i);
+              pktlen -= n;
+            }
+          else
+            {
+              n = pktlen;
+              pk->pkey[i] = mpi_read (inp, &n, 0);
+              pktlen -= n;
+              if (!pk->pkey[i])
+                err = gpg_error (GPG_ERR_INV_PACKET);
+            }
+          if (err)
+            goto leave;
+          if (list_mode)
+            {
+              es_fprintf (listfp, "\tpkey[%d]: ", i);
+              mpi_print (listfp, pk->pkey[i], mpi_print_mode);
+              es_putc ('\n', listfp);
+            }
+        }
     }
-
   if (list_mode)
     keyid_from_pk (pk, keyid);