gpg: Implement v5 keys and v5 signatures.
authorWerner Koch <wk@gnupg.org>
Thu, 14 Mar 2019 10:20:07 +0000 (11:20 +0100)
committerWerner Koch <wk@gnupg.org>
Thu, 14 Mar 2019 10:26:54 +0000 (11:26 +0100)
* g10/build-packet.c (gpg_mpi_write): New optional arg
R_NWRITTEN.  Allow NULL for OUT.  Change all callers.
(do_key): Support v5 keys.
(build_sig_subpkt_from_sig): Support 32 byte fingerprints.
* g10/parse-packet.c (parse_signature): First try to set the keyid
from the issuer fingerprint.
(parse_key): Support v5 keys.
(create_gpg_control): Better make sure to always allocate the static
size of the struct in case future compilers print warnings.
* g10/keyid.c (hash_public_key): Add v5 support.
(keyid_from_pk): Ditto.
(keyid_from_fingerprint): Ditto.
(fingerprint_from_pk): Ditto.
* g10/keygen.c (KEYGEN_FLAG_CREATE_V5_KEY): New.
(pVERSION, pSUBVERSION): New.
(add_feature_v5): New.
(keygen_upd_std_prefs): Call it.
(do_create_from_keygrip): Add arg keygen_flags and support the v5
flag.
(common_gen): Support the v5 flag.
(parse_key_parameter_part): New flags v4 and v5.
(parse_key_parameter_string): Add args for version and subversion.
(read_parameter_file): New keywords "Key-Version" and
"Subkey-Version".
(quickgen_set_para): Add arg 'version'.
(quick_generate_keypair, generate_keypair): Support version parms.
(do_generate_keypair): Support v5 key flag.
(generate_subkeypair): Ditto.
(generate_card_subkeypair): Preparse for keyflags.
(gen_card_key): Ditto.
* g10/sig-check.c (check_signature2): Add args extrahash and
extrahashlen.
(check_signature_end): Ditto.
(check_signature_end_simple): Ditto.  Use them.
* g10/mainproc.c (proc_plaintext): Put extra hash infor into the
control packet.
(do_check_sig): Add args extrahas and extrahashlen and pass them on.
(issuer_fpr_raw): Support 32 byte fingerprint.
(check_sig_and_print): get extra hash data and pass it on.
--

Note that this is only basic support and requires more fine
tuning/fixing.

Signed-off-by: Werner Koch <wk@gnupg.org>
g10/build-packet.c
g10/keygen.c
g10/keyid.c
g10/mainproc.c
g10/packet.h
g10/parse-packet.c
g10/sig-check.c
g10/sign.c

index dd4ad54..07fccb0 100644 (file)
@@ -243,12 +243,15 @@ build_packet_and_meta (iobuf_t out, PACKET *pkt)
 
 
 /*
- * Write the mpi A to OUT.
+ * Write the mpi A to OUT.  If R_NWRITTEN is not NULL the number of
+ * bytes written is stored there.  To only get the number of bytes
+ * which would be written NULL may be passed for OUT.
  */
 gpg_error_t
-gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
+gpg_mpi_write (iobuf_t out, gcry_mpi_t a, unsigned int *r_nwritten)
 {
-  int rc;
+  gpg_error_t err;
+  unsigned int nwritten = 0;
 
   if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
     {
@@ -277,9 +280,17 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
       /* gcry_log_debughex (" ", p, (nbits+7)/8); */
       lenhdr[0] = nbits >> 8;
       lenhdr[1] = nbits;
-      rc = iobuf_write (out, lenhdr, 2);
-      if (!rc && p)
-        rc = iobuf_write (out, p, (nbits+7)/8);
+      err = out? iobuf_write (out, lenhdr, 2) : 0;
+      if (!err)
+        {
+          nwritten += 2;
+          if (p)
+            {
+              err = out? iobuf_write (out, p, (nbits+7)/8) : 0;
+              if (!err)
+                nwritten += (nbits+7)/8;
+            }
+        }
     }
   else
     {
@@ -287,18 +298,25 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
       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 )
+      err = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a );
+      if (!err)
+        {
+          err = out? iobuf_write (out, buffer, nbytes) : 0;
+          if (!err)
+            nwritten += nbytes;
+        }
+      else if (gpg_err_code (err) == 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);
+          /* The buffer was too small.  We better tell the user about
+           * the MPI. */
+          err = gpg_error (GPG_ERR_TOO_LARGE);
         }
     }
 
-  return rc;
+  if (r_nwritten)
+    *r_nwritten = nwritten;
+  return err;
 }
 
 
@@ -463,29 +481,29 @@ static int
 do_key (iobuf_t out, int ctb, PKT_public_key *pk)
 {
   gpg_error_t err = 0;
-  /* The length of the body is stored in the packet's header, which
-     occurs before the body.  Unfortunately, we don't know the length
-     of the packet's body until we've written all of the data!  To
-     work around this, we first write the data into this temporary
-     buffer, then generate the header, and finally copy the contents
-     of this buffer to OUT.  */
-  iobuf_t a = iobuf_temp();
+  iobuf_t a;
   int i, nskey, npkey;
+  u32 pkbytes = 0;
+  int is_v5;
 
-  log_assert (pk->version == 0 || pk->version == 4);
+  log_assert (pk->version == 0 || pk->version == 4 || pk->version == 5);
   log_assert (ctb_pkttype (ctb) == PKT_PUBLIC_KEY
               || ctb_pkttype (ctb) == PKT_PUBLIC_SUBKEY
               || ctb_pkttype (ctb) == PKT_SECRET_KEY
               || ctb_pkttype (ctb) == PKT_SECRET_SUBKEY);
 
-  /* Write the version number - if none is specified, use 4 */
-  if ( !pk->version )
-    iobuf_put ( a, 4 );
-  else
-    iobuf_put ( a, pk->version );
-  write_32 (a, pk->timestamp );
+  /* The length of the body is stored in the packet's header, which
+   * occurs before the body.  Unfortunately, we don't know the length
+   * of the packet's body until we've written all of the data!  To
+   * work around this, we first write the data into this temporary
+   * buffer, then generate the header, and finally copy the content
+   * of this buffer to OUT.  */
+  a = iobuf_temp();
+
+  /* Note that the Version number, Timestamp, Algo, and the v5 Key
+   * material count are written at the end of the function. */
 
-  iobuf_put (a, pk->pubkey_algo );
+  is_v5 = (pk->version == 5);
 
   /* Get number of secret and public parameters.  They are held in one
      array: the public ones followed by the secret ones.  */
@@ -509,11 +527,13 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
           || (pk->pubkey_algo == PUBKEY_ALGO_ECDH  && (i == 0 || i == 2)))
         err = gpg_mpi_write_nohdr (a, pk->pkey[i]);
       else
-        err = gpg_mpi_write (a, pk->pkey[i]);
+        err = gpg_mpi_write (a, pk->pkey[i], NULL);
       if (err)
         goto leave;
     }
 
+  /* Record the length of the public key part.  */
+  pkbytes = iobuf_get_temp_length (a);
 
   if (pk->seckey_info)
     {
@@ -523,9 +543,26 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
       /* Build the header for protected (encrypted) secret parameters.  */
       if (ski->is_protected)
         {
-          /* OpenPGP protection according to rfc2440. */
-          iobuf_put (a, ski->sha1chk? 0xfe : 0xff);
-          iobuf_put (a, ski->algo);
+          iobuf_put (a, ski->sha1chk? 0xfe : 0xff); /* S2k usage.  */
+          if (is_v5)
+            {
+              /* For a v5 key determine the count of the following
+               * key-protection material and write it.  */
+              int count = 1;  /* Pubkey algo octet. */
+              if (ski->s2k.mode >= 1000)
+                count += 6;   /* GNU specific mode descriptor.  */
+              else
+                count += 2;   /* Mode and hash algo.  */
+              if (ski->s2k.mode == 1 || ski->s2k.mode == 3)
+                count += 8;   /* Salt.  */
+              if (ski->s2k.mode == 3)
+                count++;      /* S2K.COUNT */
+              if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002)
+                count += ski->ivlen;
+
+              iobuf_put (a, count);
+            }
+          iobuf_put (a, ski->algo);  /* Pubkey algo octet.  */
           if (ski->s2k.mode >= 1000)
             {
               /* These modes are not possible in OpenPGP, we use them
@@ -556,13 +593,24 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
 
         }
       else /* Not protected. */
-        iobuf_put (a, 0 );
+        {
+          iobuf_put (a, 0 );  /* S2K usage = not protected.  */
+          if (is_v5)
+            iobuf_put (a, 0); /* Zero octets of key-protection
+                               * material follows.  */
+        }
 
       if (ski->s2k.mode == 1001)
-        ; /* GnuPG extension - don't write a secret key at all. */
+        {
+          /* GnuPG extension - don't write a secret key at all. */
+          if (is_v5)
+            write_32 (a, 0); /* Zero octets of key material.  */
+        }
       else if (ski->s2k.mode == 1002)
         {
           /* GnuPG extension - divert to OpenPGP smartcard. */
+          if (is_v5)
+            write_32 (a, 1 + ski->ivlen);
           /* 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.  */
@@ -576,15 +624,36 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
 
           log_assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE));
           p = gcry_mpi_get_opaque (pk->pkey[npkey], &ndatabits);
+          /* For v5 keys we first write the number of octets of the
+           * following encrypted key material.  */
+          if (is_v5)
+            write_32 (a, p? (ndatabits+7)/8 : 0);
           if (p)
             iobuf_write (a, p, (ndatabits+7)/8 );
         }
       else
         {
           /* Non-protected key. */
+          if (is_v5)
+            {
+              unsigned int skbytes = 0;
+              unsigned int n;
+              int j;
+
+              for (j=i; j < nskey; j++ )
+                {
+                  if ((err = gpg_mpi_write (NULL, pk->pkey[j], &n)))
+                    goto leave;
+                  skbytes += n;
+                }
+
+              write_32 (a, skbytes);
+            }
+
           for ( ; i < nskey; i++ )
-            if ( (err = gpg_mpi_write (a, pk->pkey[i])))
+            if ( (err = gpg_mpi_write (a, pk->pkey[i], NULL)))
               goto leave;
+
           write_16 (a, ski->csum );
         }
     }
@@ -593,11 +662,23 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
   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), 0);
+       * writing all the other stuff, so that we know the length of
+       * the packet */
+      u32 len = iobuf_get_temp_length (a);
+      len += 1; /* version number  */
+      len += 4; /* timestamp  */
+      len += 1; /* algo  */
+      if (is_v5)
+        len += 4; /* public key material count  */
+
+      write_header2 (out, ctb, len, 0);
        /* And finally write it out to the real stream. */
-      err = iobuf_write_temp (out, a);
+      iobuf_put (out, pk->version? pk->version : 4); /* version number  */
+      write_32 (out, pk->timestamp );
+      iobuf_put (out, pk->pubkey_algo);  /* algo */
+      if (is_v5)
+        write_32 (out, pkbytes);        /* public key material count  */
+      err = iobuf_write_temp (out, a);  /* pub and sec key material */
     }
 
   iobuf_close (a); /* Close the temporary buffer */
@@ -688,7 +769,7 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
       if (enc->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
         rc = gpg_mpi_write_nohdr (a, enc->data[i]);
       else
-        rc = gpg_mpi_write (a, enc->data[i]);
+        rc = gpg_mpi_write (a, enc->data[i], NULL);
     }
 
   if (!rc)
@@ -1135,10 +1216,10 @@ build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk)
 
     /* Write the new ISSUER_FPR subpacket.  */
     fingerprint_from_pk (pksk, buf+1, &fprlen);
-    if (fprlen == 20)
+    if (fprlen == 20 || fprlen == 32)
       {
         buf[0] = pksk->version;
-        build_sig_subpkt (sig, SIGSUBPKT_ISSUER_FPR, buf, 21);
+        build_sig_subpkt (sig, SIGSUBPKT_ISSUER_FPR, buf, fprlen + 1);
       }
 
     /* Write the timestamp.  */
@@ -1567,7 +1648,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 = gpg_mpi_write (a, sig->data[i] );
+    rc = gpg_mpi_write (a, sig->data[i], NULL);
 
   if (!rc)
     {
index 61f839a..64fefd2 100644 (file)
@@ -1,6 +1,6 @@
 /* keygen.c - Generate a key pair
  * Copyright (C) 1998-2007, 2009-2011  Free Software Foundation, Inc.
- * Copyright (C) 2014, 2015, 2016  Werner Koch
+ * Copyright (C) 2014, 2015, 2016, 2017, 2018  Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -59,6 +59,7 @@ const char *default_expiration_interval = "2y";
 /* Flag bits used during key generation.  */
 #define KEYGEN_FLAG_NO_PROTECTION 1
 #define KEYGEN_FLAG_TRANSIENT_KEY 2
+#define KEYGEN_FLAG_CREATE_V5_KEY 4
 
 /* Maximum number of supported algorithm preferences.  */
 #define MAX_PREFS 30
@@ -90,7 +91,9 @@ enum para_name {
   pHANDLE,
   pKEYSERVER,
   pKEYGRIP,
-  pSUBKEYGRIP
+  pSUBKEYGRIP,
+  pVERSION,     /* Desired version of the key packet.  */
+  pSUBVERSION,  /* Ditto for the subpacket.  */
 };
 
 struct para_data_s {
@@ -148,13 +151,13 @@ static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
                                      const char *expirestr,
                                      int *r_algo, unsigned int *r_usage,
                                      u32 *r_expire, unsigned int *r_nbits,
-                                     const char **r_curve);
+                                     const char **r_curve, int *r_version);
 static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
                                  struct output_control_s *outctrl, int card );
 static int write_keyblock (iobuf_t out, kbnode_t node);
 static gpg_error_t gen_card_key (int keyno, int algo, int is_primary,
                                  kbnode_t pub_root, u32 *timestamp,
-                                 u32 expireval);
+                                 u32 expireval, int keygen_flags);
 static unsigned int get_keysize_range (int algo,
                                        unsigned int *min, unsigned int *max);
 
@@ -761,6 +764,48 @@ add_feature_aead (PKT_signature *sig, int enabled)
 
 
 static void
+add_feature_v5 (PKT_signature *sig, int enabled)
+{
+  const byte *s;
+  size_t n;
+  int i;
+  char *buf;
+
+  s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n );
+  if (s && n && ((enabled && (s[0] & 0x04)) || (!enabled && !(s[0] & 0x04))))
+    return; /* Already set or cleared */
+
+  if (!s || !n)
+    { /* Create a new one */
+      n = 1;
+      buf = xmalloc_clear (n);
+    }
+  else
+    {
+      buf = xmalloc (n);
+      memcpy (buf, s, n);
+    }
+
+  if (enabled)
+    buf[0] |= 0x04; /* v5 key supported */
+  else
+    buf[0] &= ~0x04;
+
+  /* Are there any bits set? */
+  for (i=0; i < n; i++)
+    if (buf[i])
+      break;
+
+  if (i == n)
+    delete_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES);
+  else
+    build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n);
+
+  xfree (buf);
+}
+
+
+static void
 add_keyserver_modify (PKT_signature *sig,int enabled)
 {
   const byte *s;
@@ -848,6 +893,7 @@ keygen_upd_std_prefs (PKT_signature *sig, void *opaque)
   /* Make sure that the MDC feature flag is set if needed.  */
   add_feature_mdc (sig,mdc_available);
   add_feature_aead (sig, aead_available);
+  add_feature_v5 (sig, opt.flags.rfc4880bis);
   add_keyserver_modify (sig,ks_modify);
   keygen_add_keyserver_url(sig,NULL);
 
@@ -1370,7 +1416,7 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
 static int
 do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
                         kbnode_t pub_root, u32 timestamp, u32 expireval,
-                        int is_subkey)
+                        int is_subkey, int keygen_flags)
 {
   int err;
   PACKET *pkt;
@@ -1417,7 +1463,7 @@ do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
     }
 
   pk->timestamp = timestamp;
-  pk->version = 4;
+  pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
   if (expireval)
     pk->expiredate = pk->timestamp + expireval;
   pk->pubkey_algo = algo;
@@ -1484,7 +1530,7 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
     }
 
   pk->timestamp = timestamp;
-  pk->version = 4;
+  pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
   if (expireval)
     pk->expiredate = pk->timestamp + expireval;
   pk->pubkey_algo = algo;
@@ -2928,7 +2974,7 @@ ask_user_id (int mode, int full, KBNODE keyblock)
 /* Basic key generation.  Here we divert to the actual generation
    routines based on the requested algorithm.  */
 static int
-do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root,
+do_create (int algo, unsigned int nbits, const char *curve, kbnode_t pub_root,
            u32 timestamp, u32 expiredate, int is_subkey,
            int keygen_flags, const char *passphrase,
            char **cache_nonce_addr, char **passwd_nonce_addr)
@@ -3007,12 +3053,14 @@ generate_user_id (KBNODE keyblock, const char *uidstr)
  * for any parameter.  FOR_SUBKEY shall be true if this is used as a
  * subkey.  If CLEAR_CERT is set a default CERT usage will be cleared;
  * this is useful if for example the default algorithm is used for a
- * subkey.  */
+ * subkey.  If R_KEYVERSION is not NULL it will receive the version of
+ * the key; this is currently 4 but can be changed with the flag "v5"
+ * to create a v5 key. */
 static gpg_error_t
 parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
                           int *r_algo, unsigned int *r_size,
                           unsigned int *r_keyuse,
-                          char const **r_curve)
+                          char const **r_curve, int *r_keyversion)
 {
   char *flags;
   int algo;
@@ -3021,6 +3069,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
   int ecdh_or_ecdsa = 0;
   unsigned int size;
   int keyuse;
+  int keyversion = 4;
   int i;
   const char *s;
 
@@ -3119,6 +3168,13 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
                   return gpg_error (GPG_ERR_INV_FLAG);
                 }
             }
+          else if (!ascii_strcasecmp (s, "v5"))
+            {
+              if (opt.flags.rfc4880bis)
+                keyversion = 5;
+            }
+          else if (!ascii_strcasecmp (s, "v4"))
+            keyversion = 4;
           else
             {
               xfree (tokens);
@@ -3194,10 +3250,13 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
     *r_keyuse = keyuse;
   if (r_curve)
     *r_curve = curve;
+  if (r_keyversion)
+    *r_keyversion = keyversion;
 
   return 0;
 }
 
+
 /* Parse and return the standard key generation parameter.
  * The string is expected to be in this format:
  *
@@ -3228,6 +3287,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
  *   ecdsa := Use algorithm ECDSA.
  *   eddsa := Use algorithm EdDSA.
  *   ecdh  := Use algorithm ECDH.
+ *   v5    := Create version 5 key (requires option --rfc4880bis)
  *
  * There are several defaults and fallbacks depending on the
  * algorithm.  PART can be used to select which part of STRING is
@@ -3246,9 +3306,11 @@ parse_key_parameter_string (const char *string, int part,
                             int *r_algo, unsigned int *r_size,
                             unsigned int *r_keyuse,
                             char const **r_curve,
+                            int *r_version,
                             int *r_subalgo, unsigned int *r_subsize,
-                            unsigned *r_subkeyuse,
-                            char const **r_subcurve)
+                            unsigned int *r_subkeyuse,
+                            char const **r_subcurve,
+                            int *r_subversion)
 {
   gpg_error_t err = 0;
   char *primary, *secondary;
@@ -3261,6 +3323,8 @@ parse_key_parameter_string (const char *string, int part,
     *r_keyuse = 0;
   if (r_curve)
     *r_curve = NULL;
+  if (r_version)
+    *r_version = 4;
   if (r_subalgo)
     *r_subalgo = 0;
   if (r_subsize)
@@ -3269,6 +3333,8 @@ parse_key_parameter_string (const char *string, int part,
     *r_subkeyuse = 0;
   if (r_subcurve)
     *r_subcurve = NULL;
+  if (r_subversion)
+    *r_subversion = 4;
 
   if (!string || !*string
       || !ascii_strcasecmp (string, "default") || !strcmp (string, "-"))
@@ -3283,11 +3349,11 @@ parse_key_parameter_string (const char *string, int part,
     *secondary++ = 0;
   if (part == -1 || part == 0)
     {
-      err = parse_key_parameter_part (primary, 0, 0, r_algo, r_size,
-                                      r_keyuse, r_curve);
+        err = parse_key_parameter_part (primary, 0, 0, r_algo, r_size,
+                                        r_keyuse, r_curve, r_version);
       if (!err && part == -1)
         err = parse_key_parameter_part (secondary, 1, 0, r_subalgo, r_subsize,
-                                        r_subkeyuse, r_subcurve);
+                                        r_subkeyuse, r_subcurve, r_subversion);
     }
   else if (part == 1)
     {
@@ -3300,14 +3366,17 @@ parse_key_parameter_string (const char *string, int part,
       if (secondary)
         {
           err = parse_key_parameter_part (secondary, 1, 0,
-                                          r_algo, r_size, r_keyuse, r_curve);
+                                          r_algo, r_size, r_keyuse, r_curve,
+                                          r_version);
           if (!err && suggested_use && r_keyuse && !(suggested_use & *r_keyuse))
             err = parse_key_parameter_part (primary, 1, 1 /*(clear cert)*/,
-                                            r_algo, r_size, r_keyuse, r_curve);
+                                            r_algo, r_size, r_keyuse, r_curve,
+                                            r_version);
         }
       else
         err = parse_key_parameter_part (primary, 1, 0,
-                                        r_algo, r_size, r_keyuse, r_curve);
+                                        r_algo, r_size, r_keyuse, r_curve,
+                                        r_version);
     }
 
   xfree (primary);
@@ -3395,9 +3464,8 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
        * compatibility with the batch key generation.  It would be
        * better to make full use of parse_key_parameter_string.  */
       parse_key_parameter_string (NULL, 0, 0,
-                                  &i, NULL, NULL, NULL,
-                                  NULL, NULL, NULL, NULL);
-
+                                  &i, NULL, NULL, NULL, NULL,
+                                  NULL, NULL, NULL, NULL, NULL);
       if (r_default)
         *r_default = 1;
     }
@@ -3810,6 +3878,8 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
         { "Keygrip",        pKEYGRIP },
         { "Key-Grip",       pKEYGRIP },
         { "Subkey-grip",    pSUBKEYGRIP },
+        { "Key-Version",    pVERSION },
+        { "Subkey-Version", pSUBVERSION },
         { NULL, 0 }
     };
     IOBUF fp;
@@ -3954,12 +4024,19 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
                break;
            }
        }
-       r = xmalloc_clear( sizeof *r + strlen( value ) );
-       r->lnr = lnr;
-       r->key = keywords[i].key;
-       strcpy( r->u.value, value );
-       r->next = para;
-       para = r;
+
+        if (!opt.flags.rfc4880bis && (keywords[i].key == pVERSION
+                                      || keywords[i].key == pSUBVERSION))
+          ; /* Ignore version unless --rfc4880bis is active.  */
+        else
+          {
+            r = xmalloc_clear( sizeof *r + strlen( value ) );
+            r->lnr = lnr;
+            r->key = keywords[i].key;
+            strcpy( r->u.value, value );
+            r->next = para;
+            para = r;
+          }
     }
     if( err )
        log_error("%s:%d: %s\n", fname, lnr, err );
@@ -3994,7 +4071,8 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
 /* Helper for quick_generate_keypair.  */
 static struct para_data_s *
 quickgen_set_para (struct para_data_s *para, int for_subkey,
-                   int algo, int nbits, const char *curve, unsigned int use)
+                   int algo, int nbits, const char *curve, unsigned int use,
+                   int version)
 {
   struct para_data_s *r;
 
@@ -4033,6 +4111,15 @@ quickgen_set_para (struct para_data_s *para, int for_subkey,
       para = r;
     }
 
+  if (opt.flags.rfc4880bis)
+    {
+      r = xmalloc_clear (sizeof *r + 20);
+      r->key = for_subkey? pSUBVERSION : pVERSION;
+      snprintf (r->u.value, 20, "%d", version);
+      r->next = para;
+      para = r;
+    }
+
   return para;
 }
 
@@ -4125,25 +4212,26 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
           || !strcmp (usagestr, "-")))
     {
       /* Use default key parameters.  */
-      int algo, subalgo;
+      int algo, subalgo, version, subversion;
       unsigned int size, subsize;
       unsigned int keyuse, subkeyuse;
       const char *curve, *subcurve;
 
       err = parse_key_parameter_string (algostr, -1, 0,
-                                        &algo, &size, &keyuse, &curve,
+                                        &algo, &size, &keyuse, &curve, &version,
                                         &subalgo, &subsize, &subkeyuse,
-                                        &subcurve);
+                                        &subcurve, &subversion);
       if (err)
         {
           log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
           goto leave;
         }
 
-      para = quickgen_set_para (para, 0, algo, size, curve, keyuse);
+      para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version);
       if (subalgo)
         para = quickgen_set_para (para, 1,
-                                  subalgo, subsize, subcurve, subkeyuse);
+                                  subalgo, subsize, subcurve, subkeyuse,
+                                  subversion);
 
       if (*expirestr)
         {
@@ -4166,21 +4254,22 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
   else
     {
       /* Extended unattended mode.  Creates only the primary key. */
-      int algo;
+      int algo, version;
       unsigned int use;
       u32 expire;
       unsigned int nbits;
       const char *curve;
 
       err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr,
-                                     &algo, &use, &expire, &nbits, &curve);
+                                     &algo, &use, &expire, &nbits, &curve,
+                                     &version);
       if (err)
         {
           log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
           goto leave;
         }
 
-      para = quickgen_set_para (para, 0, algo, nbits, curve, use);
+      para = quickgen_set_para (para, 0, algo, nbits, curve, use, version);
       r = xmalloc_clear (sizeof *r + 20);
       r->key = pKEYEXPIRE;
       r->u.expire = expire;
@@ -4494,7 +4583,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
     }
   else /* Default key generation.  */
     {
-      int subalgo;
+      int subalgo, version, subversion;
       unsigned int size, subsize;
       unsigned int keyuse, subkeyuse;
       const char *curve, *subcurve;
@@ -4509,18 +4598,19 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
                    , "--full-generate-key" );
 
       err = parse_key_parameter_string (NULL, -1, 0,
-                                        &algo, &size, &keyuse, &curve,
+                                        &algo, &size, &keyuse, &curve, &version,
                                         &subalgo, &subsize,
-                                        &subkeyuse, &subcurve);
+                                        &subkeyuse, &subcurve, &subversion);
       if (err)
         {
           log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
           return;
         }
-      para = quickgen_set_para (para, 0, algo, size, curve, keyuse);
+      para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version);
       if (subalgo)
         para = quickgen_set_para (para, 1,
-                                  subalgo, subsize, subcurve, subkeyuse);
+                                  subalgo, subsize, subcurve, subkeyuse,
+                                  subversion);
 
 
     }
@@ -4740,6 +4830,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
   int algo;
   u32 expire;
   const char *key_from_hexgrip = NULL;
+  unsigned int keygen_flags;
 
   if (outctrl->dryrun)
     {
@@ -4808,9 +4899,14 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
   algo = get_parameter_algo( para, pKEYTYPE, NULL );
   expire = get_parameter_u32( para, pKEYEXPIRE );
   key_from_hexgrip = get_parameter_value (para, pKEYGRIP);
+
+  keygen_flags = outctrl->keygen_flags;
+  if (get_parameter_uint (para, pVERSION) == 5)
+    keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
+
   if (key_from_hexgrip)
     err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip,
-                                  pub_root, timestamp, expire, 0);
+                                  pub_root, timestamp, expire, 0, keygen_flags);
   else if (!card)
     err = do_create (algo,
                      get_parameter_uint( para, pKEYLENGTH ),
@@ -4818,13 +4914,13 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
                      pub_root,
                      timestamp,
                      expire, 0,
-                     outctrl->keygen_flags,
+                     keygen_flags,
                      get_parameter_passphrase (para),
                      &cache_nonce, NULL);
   else
     err = gen_card_key (1, algo,
                         1, pub_root, &timestamp,
-                        expire);
+                        expire, keygen_flags);
 
   /* Get the pointer to the generated public key packet.  */
   if (!err)
@@ -4863,7 +4959,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
   if (!err && card && get_parameter (para, pAUTHKEYTYPE))
     {
       err = gen_card_key (3, get_parameter_algo( para, pAUTHKEYTYPE, NULL ),
-                          0, pub_root, &timestamp, expire);
+                          0, pub_root, &timestamp, expire, keygen_flags);
       if (!err)
         err = write_keybinding (ctrl, pub_root, pri_psk, NULL,
                                 PUBKEY_USAGE_AUTH, timestamp, cache_nonce);
@@ -4875,11 +4971,16 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
 
       s = NULL;
       key_from_hexgrip = get_parameter_value (para, pSUBKEYGRIP);
+
+      keygen_flags = outctrl->keygen_flags;
+      if (get_parameter_uint (para, pSUBVERSION) == 5)
+        keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
+
       if (key_from_hexgrip)
         err = do_create_from_keygrip (ctrl, subkey_algo, key_from_hexgrip,
                                       pub_root, timestamp,
                                       get_parameter_u32 (para, pSUBKEYEXPIRE),
-                                      1);
+                                      1, keygen_flags);
       else if (!card || (s = get_parameter_value (para, pCARDBACKUPKEY)))
         {
           err = do_create (subkey_algo,
@@ -4888,7 +4989,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
                            pub_root,
                            timestamp,
                            get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
-                           s ? KEYGEN_FLAG_NO_PROTECTION : outctrl->keygen_flags,
+                           s? KEYGEN_FLAG_NO_PROTECTION : keygen_flags,
                            get_parameter_passphrase (para),
                            &cache_nonce, NULL);
           /* Get the pointer to the generated public subkey packet.  */
@@ -4908,7 +5009,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
         }
       else
         {
-          err = gen_card_key (2, subkey_algo, 0, pub_root, &timestamp, expire);
+          err = gen_card_key (2, subkey_algo, 0, pub_root, &timestamp, expire,
+                              keygen_flags);
         }
 
       if (!err)
@@ -5032,13 +5134,15 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
                          const char *algostr, const char *usagestr,
                          const char *expirestr,
                          int *r_algo, unsigned int *r_usage, u32 *r_expire,
-                         unsigned int *r_nbits, const char **r_curve)
+                         unsigned int *r_nbits, const char **r_curve,
+                         int *r_version)
 {
   gpg_error_t err;
   int algo;
   unsigned int use, nbits;
   u32 expire;
   int wantuse;
+  int version = 4;
   const char *curve = NULL;
 
   *r_curve = NULL;
@@ -5056,8 +5160,8 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
 
   err = parse_key_parameter_string (algostr, for_subkey? 1 : 0,
                                     usagestr? parse_usagestr (usagestr):0,
-                                    &algo, &nbits, &use, &curve,
-                                    NULL, NULL, NULL, NULL);
+                                    &algo, &nbits, &use, &curve, &version,
+                                    NULL, NULL, NULL, NULL, NULL);
   if (err)
     return err;
 
@@ -5095,6 +5199,7 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
   *r_usage = use;
   *r_expire = expire;
   *r_nbits = nbits;
+  *r_version = version;
   return 0;
 }
 
@@ -5122,6 +5227,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
   char *serialno = NULL;
   char *cache_nonce = NULL;
   char *passwd_nonce = NULL;
+  int keygen_flags = 0;
 
   interactive = (!algostr || !usagestr || !expirestr);
 
@@ -5203,10 +5309,16 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
     }
   else /* Unattended mode.  */
     {
+      int version;
+
       err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr,
-                                     &algo, &use, &expire, &nbits, &curve);
+                                     &algo, &use, &expire, &nbits, &curve,
+                                     &version);
       if (err)
         goto leave;
+
+      if (version == 5)
+        keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
     }
 
   /* Verify the passphrase now so that we get a cache item for the
@@ -5229,7 +5341,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
   if (key_from_hexgrip)
     {
       err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip,
-                                    keyblock, cur_time, expire, 1);
+                                    keyblock, cur_time, expire, 1,
+                                    keygen_flags);
     }
   else
     {
@@ -5245,7 +5358,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
         passwd = NULL;
 
       err = do_create (algo, nbits, curve,
-                       keyblock, cur_time, expire, 1, 0,
+                       keyblock, cur_time, expire, 1, keygen_flags,
                        passwd, &cache_nonce, &passwd_nonce);
     }
   if (err)
@@ -5293,6 +5406,7 @@ generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock,
   PKT_public_key *sub_pk = NULL;
   int algo;
   struct agent_card_info_s info;
+  int keygen_flags = 0;  /* FIXME!!! */
 
   log_assert (keyno >= 1 && keyno <= 3);
 
@@ -5363,7 +5477,8 @@ generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock,
 
   /* Note, that depending on the backend, the card key generation may
      update CUR_TIME.  */
-  err = gen_card_key (keyno, algo, 0, pub_keyblock, &cur_time, expire);
+  err = gen_card_key (keyno, algo, 0, pub_keyblock, &cur_time, expire,
+                      keygen_flags);
   /* Get the pointer to the generated public subkey packet.  */
   if (!err)
     {
@@ -5409,10 +5524,11 @@ write_keyblock( IOBUF out, KBNODE node )
 }
 
 
-/* Note that timestamp is an in/out arg. */
+/* Note that timestamp is an in/out arg.
+ * FIXME: Does not yet support v5 keys.   */
 static gpg_error_t
 gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
-              u32 *timestamp, u32 expireval)
+              u32 *timestamp, u32 expireval, int keygen_flags)
 {
 #ifdef ENABLE_CARD_SUPPORT
   gpg_error_t err;
@@ -5486,7 +5602,7 @@ gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
     }
 
   pk->timestamp = *timestamp;
-  pk->version = 4;
+  pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
   if (expireval)
     pk->expiredate = pk->timestamp + expireval;
   pk->pubkey_algo = algo;
index 9558a26..92be959 100644 (file)
@@ -136,19 +136,21 @@ pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize)
 }
 
 
-/* Hash a public key.  This function is useful for v4 fingerprints and
  for v3 or v4 key signing. */
+/* Hash a public key.  This function is useful for v4 and v5
* fingerprints and for v3 or v4 key signing. */
 void
 hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
 {
-  unsigned int n = 6;
+  unsigned int n;
   unsigned int nn[PUBKEY_MAX_NPKEY];
   byte *pp[PUBKEY_MAX_NPKEY];
   int i;
   unsigned int nbits;
   size_t nbytes;
   int npkey = pubkey_get_npkey (pk->pubkey_algo);
+  int is_v5 = pk->version == 5;
 
+  n = is_v5? 10 : 6;
   /* FIXME: We can avoid the extra malloc by calling only the first
      mpi_print here which computes the required length and calling the
      real mpi_print only at the end.  The speed advantage would only be
@@ -201,12 +203,22 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
         }
     }
 
-  gcry_md_putc ( md, 0x99 );     /* ctb */
-  /* What does it mean if n is greater than 0xFFFF ? */
-  gcry_md_putc ( md, n >> 8 );   /* 2 byte length header */
-  gcry_md_putc ( md, n );
-  gcry_md_putc ( md, pk->version );
-
+  if (is_v5)
+    {
+      gcry_md_putc ( md, 0x9a );     /* ctb */
+      gcry_md_putc ( md, n >> 24 );  /* 4 byte length header */
+      gcry_md_putc ( md, n >> 16 );
+      gcry_md_putc ( md, n >>  8 );
+      gcry_md_putc ( md, n       );
+      gcry_md_putc ( md, pk->version );
+    }
+  else
+    {
+      gcry_md_putc ( md, 0x99 );     /* ctb */
+      gcry_md_putc ( md, n >> 8 );   /* 2 byte length header */
+      gcry_md_putc ( md, n );
+      gcry_md_putc ( md, pk->version );
+    }
   gcry_md_putc ( md, pk->timestamp >> 24 );
   gcry_md_putc ( md, pk->timestamp >> 16 );
   gcry_md_putc ( md, pk->timestamp >>  8 );
@@ -214,6 +226,15 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
 
   gcry_md_putc ( md, pk->pubkey_algo );
 
+  if (is_v5)
+    {
+      n -= 10;
+      gcry_md_putc ( md, n >> 24 );
+      gcry_md_putc ( md, n >> 16 );
+      gcry_md_putc ( md, n >>  8 );
+      gcry_md_putc ( md, n       );
+    }
+
   if(npkey==0 && pk->pkey[0]
      && gcry_mpi_get_flag (pk->pkey[0], GCRYMPI_FLAG_OPAQUE))
     {
@@ -237,10 +258,10 @@ do_fingerprint_md( PKT_public_key *pk )
 {
   gcry_md_hd_t md;
 
-  if (gcry_md_open (&md, DIGEST_ALGO_SHA1, 0))
+  if (gcry_md_open (&md, pk->version == 5 ? GCRY_MD_SHA256 : GCRY_MD_SHA1, 0))
     BUG ();
-  hash_public_key(md,pk);
-  gcry_md_final( md );
+  hash_public_key (md,pk);
+  gcry_md_final (md);
 
   return md;
 }
@@ -517,13 +538,12 @@ keystr_from_desc(KEYDB_SEARCH_DESC *desc)
 
 
 /*
- * Get the keyid from the public key and put it into keyid
- * if this is not NULL. Return the 32 low bits of the keyid.
+ * Get the keyid from the public key PK and store it at KEYID unless
+ * this is NULL.  Returns the 32 bit short keyid.
  */
 u32
 keyid_from_pk (PKT_public_key *pk, u32 *keyid)
 {
-  u32 lowbits;
   u32 dummy_keyid[2];
 
   if (!keyid)
@@ -533,7 +553,6 @@ keyid_from_pk (PKT_public_key *pk, u32 *keyid)
     {
       keyid[0] = pk->keyid[0];
       keyid[1] = pk->keyid[1];
-      lowbits = keyid[1];
     }
   else
     {
@@ -544,18 +563,25 @@ keyid_from_pk (PKT_public_key *pk, u32 *keyid)
       if(md)
        {
          dp = gcry_md_read ( md, 0 );
-         keyid[0] = buf32_to_u32 (dp+12);
-         keyid[1] = buf32_to_u32 (dp+16);
-         lowbits = keyid[1];
+          if (pk->version == 5)
+            {
+              keyid[0] = buf32_to_u32 (dp);
+              keyid[1] = buf32_to_u32 (dp+4);
+            }
+          else
+            {
+              keyid[0] = buf32_to_u32 (dp+12);
+              keyid[1] = buf32_to_u32 (dp+16);
+            }
          gcry_md_close (md);
          pk->keyid[0] = keyid[0];
          pk->keyid[1] = keyid[1];
        }
       else
-       pk->keyid[0]=pk->keyid[1]=keyid[0]=keyid[1]=lowbits=0xFFFFFFFF;
+       pk->keyid[0] = pk->keyid[1] = keyid[0]= keyid[1] = 0xFFFFFFFF;
     }
 
-  return lowbits;
+  return keyid[1]; /*FIXME:shortkeyid ist different for v5*/
 }
 
 
@@ -594,8 +620,16 @@ keyid_from_fingerprint (ctrl_t ctrl, const byte *fprint,
   else
     {
       const byte *dp = fprint;
-      keyid[0] = buf32_to_u32 (dp+12);
-      keyid[1] = buf32_to_u32 (dp+16);
+      if (fprint_len == 20)  /* v4 key */
+        {
+          keyid[0] = buf32_to_u32 (dp+12);
+          keyid[1] = buf32_to_u32 (dp+16);
+        }
+      else  /* v5 key */
+        {
+          keyid[0] = buf32_to_u32 (dp);
+          keyid[1] = buf32_to_u32 (dp+4);
+        }
     }
 
   return keyid[1];
@@ -610,7 +644,7 @@ keyid_from_sig (PKT_signature *sig, u32 *keyid)
       keyid[0] = sig->keyid[0];
       keyid[1] = sig->keyid[1];
     }
-  return sig->keyid[1];
+  return sig->keyid[1];  /*FIXME:shortkeyid*/
 }
 
 
@@ -800,15 +834,23 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
   size_t len;
   gcry_md_hd_t md;
 
-  md = do_fingerprint_md(pk);
-  dp = gcry_md_read( md, 0 );
+  md = do_fingerprint_md (pk);
+  dp = gcry_md_read (md, 0);
   len = gcry_md_get_algo_dlen (gcry_md_get_algo (md));
-  log_assert( len <= MAX_FINGERPRINT_LEN );
+  log_assert (len <= MAX_FINGERPRINT_LEN);
   if (!array)
     array = xmalloc ( len );
   memcpy (array, dp, len );
-  pk->keyid[0] = buf32_to_u32 (dp+12);
-  pk->keyid[1] = buf32_to_u32 (dp+16);
+  if (pk->version == 5)
+    {
+      pk->keyid[0] = buf32_to_u32 (dp);
+      pk->keyid[1] = buf32_to_u32 (dp+4);
+    }
+  else
+    {
+      pk->keyid[0] = buf32_to_u32 (dp+12);
+      pk->keyid[1] = buf32_to_u32 (dp+16);
+    }
   gcry_md_close( md);
 
   if (ret_len)
index 8c41088..6fa30e0 100644 (file)
@@ -829,6 +829,8 @@ proc_plaintext( CTX c, PACKET *pkt )
   PKT_plaintext *pt = pkt->pkt.plaintext;
   int any, clearsig, rc;
   kbnode_t n;
+  unsigned char *extrahash;
+  size_t extrahashlen;
 
   /* This is a literal data packet.  Bump a counter for later checks.  */
   literals_seen++;
@@ -948,8 +950,33 @@ proc_plaintext( CTX c, PACKET *pkt )
   c->last_was_session_key = 0;
 
   /* We add a marker control packet instead of the plaintext packet.
-   * This is so that we can later detect invalid packet sequences.  */
-  n = new_kbnode (create_gpg_control (CTRLPKT_PLAINTEXT_MARK, NULL, 0));
+   * This is so that we can later detect invalid packet sequences.
+   * The apcket is further used to convey extra data from the
+   * plaintext packet to the signature verification. */
+  extrahash = xtrymalloc (6 + pt->namelen);
+  if (!extrahash)
+    {
+      /* No way to return an error.  */
+      rc = gpg_error_from_syserror ();
+      log_error ("malloc failed in %s: %s\n", __func__, gpg_strerror (rc));
+      extrahashlen = 0;
+    }
+  else
+    {
+      extrahash[0] = pt->mode;
+      extrahash[1] = pt->namelen;
+      if (pt->namelen)
+        memcpy (extrahash+2, pt->name, pt->namelen);
+      extrahashlen = 2 + pt->namelen;
+      extrahash[extrahashlen++] = pt->timestamp >> 24;
+      extrahash[extrahashlen++] = pt->timestamp >> 16;
+      extrahash[extrahashlen++] = pt->timestamp >>  8;
+      extrahash[extrahashlen++] = pt->timestamp      ;
+    }
+
+  n = new_kbnode (create_gpg_control (CTRLPKT_PLAINTEXT_MARK,
+                                      extrahash, extrahashlen));
+  xfree (extrahash);
   if (c->list)
     add_kbnode (c->list, n);
   else
@@ -1019,7 +1046,8 @@ proc_compressed (CTX c, PACKET *pkt)
  * found.  Returns: 0 = valid signature or an error code
  */
 static int
-do_check_sig (CTX c, kbnode_t node, int *is_selfsig,
+do_check_sig (CTX c, kbnode_t node, const void *extrahash, size_t extrahashlen,
+              int *is_selfsig,
              int *is_expkey, int *is_revkey, PKT_public_key **r_pk)
 {
   PKT_signature *sig;
@@ -1105,14 +1133,16 @@ do_check_sig (CTX c, kbnode_t node, int *is_selfsig,
 
   /* We only get here if we are checking the signature of a binary
      (0x00) or text document (0x01).  */
-  rc = check_signature2 (c->ctrl, sig, md, NULL, is_expkey, is_revkey, r_pk);
+  rc = check_signature2 (c->ctrl, sig, md, extrahash, extrahashlen,
+                         NULL, is_expkey, is_revkey, r_pk);
   if (! rc)
     md_good = md;
   else if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2)
     {
       PKT_public_key *pk2;
 
-      rc = check_signature2 (c->ctrl, sig, md2, NULL, is_expkey, is_revkey,
+      rc = check_signature2 (c->ctrl, sig, md2, extrahash, extrahashlen,
+                             NULL, is_expkey, is_revkey,
                              r_pk? &pk2 : NULL);
       if (!rc)
         {
@@ -1275,7 +1305,7 @@ list_node (CTX c, kbnode_t node)
       if (opt.check_sigs)
         {
           fflush (stdout);
-          rc2 = do_check_sig (c, node, &is_selfsig, NULL, NULL, NULL);
+          rc2 = do_check_sig (c, node, NULL, 0, &is_selfsig, NULL, NULL, NULL);
           switch (gpg_err_code (rc2))
             {
             case 0:                      sigrc = '!'; break;
@@ -1738,7 +1768,7 @@ akl_has_wkd_method (void)
 }
 
 
-/* Return the ISSUER fingerprint buffer and its lenbgth at R_LEN.
+/* Return the ISSUER fingerprint buffer and its length at R_LEN.
  * Returns NULL if not available.  The returned buffer is valid as
  * long as SIG is not modified.  */
 const byte *
@@ -1748,7 +1778,7 @@ issuer_fpr_raw (PKT_signature *sig, size_t *r_len)
   size_t n;
 
   p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n);
-  if (p && n == 21 && p[0] == 4)
+  if (p && ((n == 21 && p[0] == 4) || (n == 33 && p[0] == 5)))
     {
       *r_len = n - 1;
       return p+1;
@@ -1811,6 +1841,8 @@ check_sig_and_print (CTX c, kbnode_t node)
   char *issuer_fpr = NULL;
   PKT_public_key *pk = NULL;  /* The public key for the signature or NULL. */
   int tried_ks_by_fpr;
+  const void *extrahash = NULL;
+  size_t extrahashlen = 0;
 
   if (opt.skip_verify)
     {
@@ -1868,6 +1900,8 @@ check_sig_and_print (CTX c, kbnode_t node)
           {
             if (n->next)
               goto ambiguous;  /* We only allow one P packet. */
+            extrahash = n->pkt->pkt.gpg_control->data;
+            extrahashlen = n->pkt->pkt.gpg_control->datalen;
           }
         else
           goto ambiguous;
@@ -1882,6 +1916,9 @@ check_sig_and_print (CTX c, kbnode_t node)
                     && (n->pkt->pkt.gpg_control->control
                         == CTRLPKT_PLAINTEXT_MARK)))
           goto ambiguous;
+        extrahash = n->pkt->pkt.gpg_control->data;
+        extrahashlen = n->pkt->pkt.gpg_control->datalen;
+
         for (n_sig=0, n = n->next;
              n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
           n_sig++;
@@ -1912,6 +1949,8 @@ check_sig_and_print (CTX c, kbnode_t node)
                     && (n->pkt->pkt.gpg_control->control
                         == CTRLPKT_PLAINTEXT_MARK)))
           goto ambiguous;
+        extrahash = n->pkt->pkt.gpg_control->data;
+        extrahashlen = n->pkt->pkt.gpg_control->datalen;
         for (n_sig=0, n = n->next;
              n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
           n_sig++;
@@ -1957,7 +1996,8 @@ check_sig_and_print (CTX c, kbnode_t node)
   if (sig->signers_uid)
     log_info (_("               issuer \"%s\"\n"), sig->signers_uid);
 
-  rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk);
+  rc = do_check_sig (c, node, extrahash, extrahashlen,
+                     NULL, &is_expkey, &is_revkey, &pk);
 
   /* If the key isn't found, check for a preferred keyserver.  */
   if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && sig->flags.pref_ks)
@@ -1992,8 +2032,8 @@ check_sig_and_print (CTX c, kbnode_t node)
                   res = keyserver_import_keyid (c->ctrl, sig->keyid,spec, 1);
                   glo_ctrl.in_auto_key_retrieve--;
                   if (!res)
-                    rc = do_check_sig (c, node, NULL,
-                                       &is_expkey, &is_revkey, &pk);
+                    rc = do_check_sig (c, node, extrahash, extrahashlen,
+                                       NULL, &is_expkey, &is_revkey, &pk);
                   free_keyserver_spec (spec);
 
                   if (!rc)
@@ -2028,7 +2068,8 @@ check_sig_and_print (CTX c, kbnode_t node)
               glo_ctrl.in_auto_key_retrieve--;
               free_keyserver_spec (spec);
               if (!res)
-                rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk);
+                rc = do_check_sig (c, node, extrahash, extrahashlen,
+                                   NULL, &is_expkey, &is_revkey, &pk);
             }
         }
     }
@@ -2050,7 +2091,7 @@ check_sig_and_print (CTX c, kbnode_t node)
       p = issuer_fpr_raw (sig, &n);
       if (p)
         {
-          /* v4 packet with a SHA-1 fingerprint.  */
+          /* v4 or v5 packet with a SHA-1/256 fingerprint.  */
           free_public_key (pk);
           pk = NULL;
           glo_ctrl.in_auto_key_retrieve++;
@@ -2058,7 +2099,8 @@ check_sig_and_print (CTX c, kbnode_t node)
           tried_ks_by_fpr = 1;
           glo_ctrl.in_auto_key_retrieve--;
           if (!res)
-            rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk);
+            rc = do_check_sig (c, node, extrahash, extrahashlen,
+                               NULL, &is_expkey, &is_revkey, &pk);
         }
     }
 
@@ -2080,7 +2122,8 @@ check_sig_and_print (CTX c, kbnode_t node)
       /* Fixme: If the fingerprint is embedded in the signature,
        * compare it to the fingerprint of the returned key.  */
       if (!res)
-        rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk);
+        rc = do_check_sig (c, node, extrahash, extrahashlen,
+                           NULL, &is_expkey, &is_revkey, &pk);
     }
 
   /* If the above methods did't work, our next try is to use a
@@ -2098,7 +2141,8 @@ check_sig_and_print (CTX c, kbnode_t node)
       res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver, 1);
       glo_ctrl.in_auto_key_retrieve--;
       if (!res)
-        rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk);
+        rc = do_check_sig (c, node, extrahash, extrahashlen,
+                           NULL, &is_expkey, &is_revkey, &pk);
     }
 
   if (!rc || gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE)
index 6160d0b..41dd1a9 100644 (file)
@@ -853,7 +853,7 @@ PACKET *create_gpg_control ( ctrlpkttype_t type,
 /*-- build-packet.c --*/
 int build_packet (iobuf_t out, PACKET *pkt);
 gpg_error_t build_packet_and_meta (iobuf_t out, PACKET *pkt);
-gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a);
+gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a, unsigned int *t_nwritten);
 gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a);
 u32 calc_packet_length( PACKET *pkt );
 void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
@@ -900,6 +900,7 @@ int check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest);
  * it and verifying the signature.  */
 gpg_error_t check_signature2 (ctrl_t ctrl,
                               PKT_signature *sig, gcry_md_hd_t digest,
+                              const void *extrahash, size_t extrahashlen,
                               u32 *r_expiredate, int *r_expired, int *r_revoked,
                               PKT_public_key **r_pk);
 
index 21a26c7..5b4b1c9 100644 (file)
@@ -1644,7 +1644,7 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type)
       if (n < 8)
        break;
       return 0;
-    case SIGSUBPKT_ISSUER_FPR: /* issuer key ID */
+    case SIGSUBPKT_ISSUER_FPR: /* issuer key fingerprint */
       if (n < 21)
        break;
       return 0;
@@ -2078,10 +2078,23 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
               && opt.verbose)
        log_info ("signature packet without timestamp\n");
 
-      p = parse_sig_subpkt2 (sig, SIGSUBPKT_ISSUER);
-      if (p)
-       {
-         sig->keyid[0] = buf32_to_u32 (p);
+      /* Set the key id.  We first try the issuer fingerprint and if
+       * it is a v4 signature the fallback to the issuer.  Note that
+       * only the issuer packet is also searched in the unhashed area.  */
+      p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &len);
+      if (p && len == 21 && p[0] == 4)
+        {
+          sig->keyid[0] = buf32_to_u32 (p + 1 + 12);
+         sig->keyid[1] = buf32_to_u32 (p + 1 + 16);
+       }
+      else if (p && len == 33 && p[0] == 5)
+        {
+          sig->keyid[0] = buf32_to_u32 (p + 1 );
+         sig->keyid[1] = buf32_to_u32 (p + 1 + 4);
+       }
+      else if ((p = parse_sig_subpkt2 (sig, SIGSUBPKT_ISSUER)))
+        {
+          sig->keyid[0] = buf32_to_u32 (p);
          sig->keyid[1] = buf32_to_u32 (p + 4);
        }
       else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110)
@@ -2287,6 +2300,9 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
   int npkey, nskey;
   u32 keyid[2];
   PKT_public_key *pk;
+  int is_v5;
+  unsigned int pkbytes; /* For v5 keys: Number of bytes in the public
+                         * key material.  For v4 keys: 0.  */
 
   (void) hdr;
 
@@ -2318,12 +2334,13 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
       return 0;
     }
   else if (version == 4)
-    {
-      /* The only supported version.  Use an older gpg
-         version (i.e. gpg 1.4) to parse v3 packets.  */
-    }
+    is_v5 = 0;
+  else if (version == 5)
+    is_v5 = 1;
   else if (version == 2 || version == 3)
     {
+      /* Not anymore supported since 2.1.  Use an older gpg version
+       * (i.e. gpg 1.4) to parse v3 packets.  */
       if (opt.verbose > 1)
         log_info ("packet(%d) with obsolete version %d\n", pkttype, version);
       if (list_mode)
@@ -2341,7 +2358,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
       goto leave;
     }
 
-  if (pktlen < 11)
+  if (pktlen < (is_v5? 15:11))
     {
       log_error ("packet(%d) too short\n", pkttype);
       if (list_mode)
@@ -2364,14 +2381,28 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
   max_expiredate = 0;
   algorithm = iobuf_get_noeof (inp);
   pktlen--;
+  if (is_v5)
+    {
+      pkbytes = read_32 (inp);
+      pktlen -= 4;
+    }
+  else
+    pkbytes = 0;
+
   if (list_mode)
-    es_fprintf (listfp, ":%s key packet:\n"
-                "\tversion %d, algo %d, created %lu, expires %lu\n",
-                pkttype == PKT_PUBLIC_KEY ? "public" :
-                pkttype == PKT_SECRET_KEY ? "secret" :
-                pkttype == PKT_PUBLIC_SUBKEY ? "public sub" :
-                pkttype == PKT_SECRET_SUBKEY ? "secret sub" : "??",
-                version, algorithm, timestamp, expiredate);
+    {
+      es_fprintf (listfp, ":%s key packet:\n"
+                  "\tversion %d, algo %d, created %lu, expires %lu",
+                  pkttype == PKT_PUBLIC_KEY ? "public" :
+                  pkttype == PKT_SECRET_KEY ? "secret" :
+                  pkttype == PKT_PUBLIC_SUBKEY ? "public sub" :
+                  pkttype == PKT_SECRET_SUBKEY ? "secret sub" : "??",
+                  version, algorithm, timestamp, expiredate);
+      if (is_v5)
+        es_fprintf (listfp, ", pkbytes %u\n", pkbytes);
+      else
+        es_fprintf (listfp, "\n");
+    }
 
   pk->timestamp = timestamp;
   pk->expiredate = expiredate;
@@ -2446,6 +2477,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
       struct seckey_info *ski;
       byte temp[16];
       size_t snlen = 0;
+      unsigned int skbytes;
 
       if (pktlen < 1)
         {
@@ -2462,23 +2494,42 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
 
       ski->algo = iobuf_get_noeof (inp);
       pktlen--;
+
+      if (is_v5)
+        {
+          unsigned int protcount = 0;
+
+          /* Read the one octet count of the following key-protection
+           * material.  Only required in case of unknown values. */
+          if (!pktlen)
+            {
+              err = gpg_error (GPG_ERR_INV_PACKET);
+              goto leave;
+            }
+          protcount = iobuf_get_noeof (inp);
+          pktlen--;
+          if (list_mode)
+            es_fprintf (listfp, "\tprotbytes: %u\n", protcount);
+        }
+
       if (ski->algo)
        {
          ski->is_protected = 1;
          ski->s2k.count = 0;
          if (ski->algo == 254 || ski->algo == 255)
            {
-             if (pktlen < 3)
+              if (pktlen < 3)
                {
                  err = gpg_error (GPG_ERR_INV_PACKET);
                  goto leave;
                }
-             ski->sha1chk = (ski->algo == 254);
+
+              ski->sha1chk = (ski->algo == 254);
              ski->algo = iobuf_get_noeof (inp);
              pktlen--;
              /* Note that a ski->algo > 110 is illegal, but I'm not
-                erroring on it here as otherwise there would be no
-                way to delete such a key.  */
+              * erroring out here as otherwise there would be no way
+              * to delete such a key.  */
              ski->s2k.mode = iobuf_get_noeof (inp);
              pktlen--;
              ski->s2k.hash_algo = iobuf_get_noeof (inp);
@@ -2504,10 +2555,8 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
                }
 
               /* Read the salt.  */
-             switch (ski->s2k.mode)
+             if (ski->s2k.mode == 3 || ski->s2k.mode == 1)
                {
-               case 1:
-               case 3:
                  for (i = 0; i < 8 && pktlen; i++, pktlen--)
                    temp[i] = iobuf_get_noeof (inp);
                   if (i < 8)
@@ -2516,7 +2565,6 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
                      goto leave;
                     }
                  memcpy (ski->s2k.salt, temp, 8);
-                 break;
                }
 
               /* Check the mode.  */
@@ -2616,7 +2664,9 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
           *   ski->ivlen = cipher_get_blocksize (ski->algo);
           * won't work.  The only solution I see is to hardwire it.
           * NOTE: if you change the ivlen above 16, don't forget to
-          * enlarge temp.  */
+          * enlarge temp.
+           * FIXME: For v5 keys we can deduce this info!
+           */
          ski->ivlen = openpgp_cipher_blocklen (ski->algo);
          log_assert (ski->ivlen <= sizeof (temp));
 
@@ -2644,6 +2694,20 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
          memcpy (ski->iv, temp, ski->ivlen);
        }
 
+      /* Skip count of secret key material.  */
+      if (is_v5)
+        {
+          if (pktlen < 4)
+            {
+              err = gpg_error (GPG_ERR_INV_PACKET);
+              goto leave;
+            }
+          skbytes = read_32 (inp);
+          pktlen -= 4;
+          if (list_mode)
+            es_fprintf (listfp, "\tskbytes: %u\n", skbytes);
+        }
+
       /* It does not make sense to read it into secure memory.
        * If the user is so careless, not to protect his secret key,
        * we can assume, that he operates an open system :=(.
@@ -2666,13 +2730,14 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
 
          /* Ugly: The length is encrypted too, so we read all stuff
           * up to the end of the packet into the first SKEY
-          * element.  */
+          * element.
+           * FIXME: We can do better for v5 keys.  */
          pk->pkey[npkey] = gcry_mpi_set_opaque (NULL,
                                                 read_rest (inp, pktlen),
                                                 pktlen * 8);
           /* Mark that MPI as protected - we need this information for
-             importing a key.  The OPAQUE flag can't be used because
-             we also store public EdDSA values in opaque MPIs.  */
+           * importing a key.  The OPAQUE flag can't be used because
+           * we also store public EdDSA values in opaque MPIs.  */
           if (pk->pkey[npkey])
             gcry_mpi_set_flag (pk->pkey[npkey], GCRYMPI_FLAG_USER1);
          pktlen = 0;
@@ -3509,11 +3574,13 @@ create_gpg_control (ctrlpkttype_t type, const byte * data, size_t datalen)
   PACKET *packet;
   byte *p;
 
+  if (!data)
+    datalen = 0;
+
   packet = xmalloc (sizeof *packet);
   init_packet (packet);
   packet->pkttype = PKT_GPG_CONTROL;
-  packet->pkt.gpg_control = xmalloc (sizeof *packet->pkt.gpg_control
-                                    + datalen - 1);
+  packet->pkt.gpg_control = xmalloc (sizeof *packet->pkt.gpg_control + datalen);
   packet->pkt.gpg_control->control = type;
   packet->pkt.gpg_control->datalen = datalen;
   p = packet->pkt.gpg_control->data;
index e8782f9..e7f97de 100644 (file)
 
 static int check_signature_end (PKT_public_key *pk, PKT_signature *sig,
                                gcry_md_hd_t digest,
+                                const void *extrahash, size_t extrahashlen,
                                int *r_expired, int *r_revoked,
                                PKT_public_key *ret_pk);
 
 static int check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
-                                       gcry_md_hd_t digest);
+                                       gcry_md_hd_t digest,
+                                       const void *extrahash,
+                                       size_t extrahashlen);
 
 
 /* Statistics for signature verification.  */
@@ -69,7 +72,7 @@ sig_check_dump_stats (void)
 int
 check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest)
 {
-  return check_signature2 (ctrl, sig, digest, NULL, NULL, NULL, NULL);
+  return check_signature2 (ctrl, sig, digest, NULL, 0, NULL, NULL, NULL, NULL);
 }
 
 
@@ -95,6 +98,9 @@ check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest)
  * signature data from the version number through the hashed subpacket
  * data (inclusive) is hashed.")
  *
+ * EXTRAHASH and EXTRAHASHLEN is additional data which is hashed with
+ * v5 signatures.  They may be NULL to use the default.
+ *
  * If R_EXPIREDATE is not NULL, R_EXPIREDATE is set to the key's
  * expiry.
  *
@@ -112,7 +118,9 @@ check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest)
  * Returns 0 on success.  An error code otherwise.  */
 gpg_error_t
 check_signature2 (ctrl_t ctrl,
-                  PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
+                  PKT_signature *sig, gcry_md_hd_t digest,
+                  const void *extrahash, size_t extrahashlen,
+                  u32 *r_expiredate,
                  int *r_expired, int *r_revoked, PKT_public_key **r_pk)
 {
   int rc=0;
@@ -179,7 +187,8 @@ check_signature2 (ctrl_t ctrl,
       if (r_expiredate)
         *r_expiredate = pk->expiredate;
 
-      rc = check_signature_end (pk, sig, digest, r_expired, r_revoked, NULL);
+      rc = check_signature_end (pk, sig, digest, extrahash, extrahashlen,
+                                r_expired, r_revoked, NULL);
 
       /* Check the backsig.  This is a back signature (0x19) from
        * the subkey on the primary key.  The idea here is that it
@@ -424,6 +433,7 @@ check_signature_metadata_validity (PKT_public_key *pk, PKT_signature *sig,
 static int
 check_signature_end (PKT_public_key *pk, PKT_signature *sig,
                     gcry_md_hd_t digest,
+                     const void *extrahash, size_t extrahashlen,
                     int *r_expired, int *r_revoked, PKT_public_key *ret_pk)
 {
   int rc = 0;
@@ -432,7 +442,8 @@ check_signature_end (PKT_public_key *pk, PKT_signature *sig,
                                                r_expired, r_revoked)))
     return rc;
 
-  if ((rc = check_signature_end_simple (pk, sig, digest)))
+  if ((rc = check_signature_end_simple (pk, sig, digest,
+                                        extrahash, extrahashlen)))
     return rc;
 
   if (!rc && ret_pk)
@@ -447,7 +458,8 @@ check_signature_end (PKT_public_key *pk, PKT_signature *sig,
  * expiration, revocation, etc.  */
 static int
 check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
-                            gcry_md_hd_t digest)
+                            gcry_md_hd_t digest,
+                            const void *extrahash, size_t extrahashlen)
 {
   gcry_mpi_t result = NULL;
   int rc = 0;
@@ -539,8 +551,13 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
           /* - One octet content format
            * - File name (one octet length followed by the name)
            * - Four octet timestamp */
-          memset (buf, 0, 6);
-          gcry_md_write (digest, buf, 6);
+          if (extrahash && extrahashlen)
+            gcry_md_write (digest, extrahash, extrahashlen);
+          else /* Detached signature. */
+            {
+              memset (buf, 0, 6);
+              gcry_md_write (digest, buf, 6);
+            }
         }
       /* Add some magic per Section 5.2.4 of RFC 4880.  */
       i = 0;
@@ -790,7 +807,7 @@ check_backsig (PKT_public_key *main_pk,PKT_public_key *sub_pk,
     {
       hash_public_key(md,main_pk);
       hash_public_key(md,sub_pk);
-      rc = check_signature_end (sub_pk, backsig, md, NULL, NULL, NULL);
+      rc = check_signature_end (sub_pk, backsig, md, NULL, 0, NULL, NULL, NULL);
       cache_sig_result(backsig,rc);
       gcry_md_close(md);
     }
@@ -977,28 +994,28 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer,
     {
       log_assert (packet->pkttype == PKT_PUBLIC_KEY);
       hash_public_key (md, packet->pkt.public_key);
-      rc = check_signature_end_simple (signer, sig, md);
+      rc = check_signature_end_simple (signer, sig, md, NULL, 0);
     }
   else if (IS_BACK_SIG (sig))
     {
       log_assert (packet->pkttype == PKT_PUBLIC_KEY);
       hash_public_key (md, packet->pkt.public_key);
       hash_public_key (md, signer);
-      rc = check_signature_end_simple (signer, sig, md);
+      rc = check_signature_end_simple (signer, sig, md, NULL, 0);
     }
   else if (IS_SUBKEY_SIG (sig) || IS_SUBKEY_REV (sig))
     {
       log_assert (packet->pkttype == PKT_PUBLIC_SUBKEY);
       hash_public_key (md, pripk);
       hash_public_key (md, packet->pkt.public_key);
-      rc = check_signature_end_simple (signer, sig, md);
+      rc = check_signature_end_simple (signer, sig, md, NULL, 0);
     }
   else if (IS_UID_SIG (sig) || IS_UID_REV (sig))
     {
       log_assert (packet->pkttype == PKT_USER_ID);
       hash_public_key (md, pripk);
       hash_uid_packet (packet->pkt.user_id, md, sig);
-      rc = check_signature_end_simple (signer, sig, md);
+      rc = check_signature_end_simple (signer, sig, md, NULL, 0);
     }
   else
     {
index 67556d8..176940b 100644 (file)
 #define LF "\n"
 #endif
 
+/* Hack */
+static int recipient_digest_algo;
+
+
 /* A type for the extra data we hash into v5 signature packets.  */
 struct pt_extra_hash_data_s
 {
@@ -60,10 +64,6 @@ struct pt_extra_hash_data_s
 typedef struct pt_extra_hash_data_s *pt_extra_hash_data_t;
 
 
-/* Hack */
-static int recipient_digest_algo;
-
-
 /*
  * Create notations and other stuff.  It is assumed that the strings in
  * STRLIST are already checked to contain only printable data and have
@@ -746,8 +746,8 @@ write_plaintext_packet (iobuf_t out, iobuf_t inp,
           (*r_extrahash)->mode = pt->mode;
           (*r_extrahash)->timestamp = pt->timestamp;
           (*r_extrahash)->namelen = pt->namelen;
-          /* Note that the last byte or NAME won't be initialized
-           * becuase we don't need it.  */
+          /* Note that the last byte of NAME won't be initialized
+           * because we don't need it.  */
           memcpy ((*r_extrahash)->name, pt->name, pt->namelen);
         }
       pt->buf = NULL;