* main.h, seskey.c (encode_md_value): Modify to allow a q size greater
authorDavid Shaw <dshaw@jabberwocky.com>
Thu, 30 Mar 2006 19:20:59 +0000 (19:20 +0000)
committerDavid Shaw <dshaw@jabberwocky.com>
Thu, 30 Mar 2006 19:20:59 +0000 (19:20 +0000)
than 160 bits as per DSA2.  This will allow us to verify and issue DSA2
signatures for some backwards compatibility once we start generating DSA2
keys.
* sign.c (do_sign), sig-check.c (do_check): Change all callers.

* sign.c (do_sign): Enforce the 160-bit check for new signatures here
since encode_md_value can handle non-160-bit digests now. This will need
to come out once the standard for DSA2 is firmed up.

g10/ChangeLog
g10/main.h
g10/seskey.c
g10/sig-check.c
g10/sign.c

index 18c7299..750c1b3 100644 (file)
@@ -1,3 +1,16 @@
+2006-03-30  David Shaw  <dshaw@jabberwocky.com>
+
+       * main.h, seskey.c (encode_md_value): Modify to allow a q size
+       greater than 160 bits as per DSA2.  This will allow us to verify
+       and issue DSA2 signatures for some backwards compatibility once we
+       start generating DSA2 keys.     
+       * sign.c (do_sign), sig-check.c (do_check): Change all callers.
+
+       * sign.c (do_sign): Enforce the 160-bit check for new signatures
+       here since encode_md_value can handle non-160-bit digests now.
+       This will need to come out once the standard for DSA2 is firmed
+       up.
+
 2006-03-22  David Shaw  <dshaw@jabberwocky.com>
 
        * getkey.c (parse_auto_key_locate): Silently strip out duplicates
index ac337fa..434ecc2 100644 (file)
@@ -203,8 +203,8 @@ void try_make_homedir( const char *fname );
 /*-- seskey.c --*/
 void make_session_key( DEK *dek );
 MPI encode_session_key( DEK *dek, unsigned nbits );
-MPI encode_md_value( int pubkey_algo, MD_HANDLE md,
-                    int hash_algo, unsigned nbits );
+MPI encode_md_value( PKT_public_key *pk, PKT_secret_key *sk,
+                    MD_HANDLE md, int hash_algo );
 
 /*-- import.c --*/
 int parse_import_options(char *str,unsigned int *options,int noisy);
index adf85c9..9685bf5 100644 (file)
@@ -195,36 +195,76 @@ do_encode_md( MD_HANDLE md, int algo, size_t len, unsigned nbits,
 
 /****************
  * Encode a message digest into an MPI.
- * v3compathack is used to work around a bug in old GnuPG versions
- * which did put the algo identifier inseatd of the block type 1 into
- * the encoded value.  Setting this flag forces the old behaviour.
+ * If it's for a DSA signature, make sure that the hash is large
+ * enough to fill up q.  If the hash is too big, take the leftmost
+ * bits.
  */
 MPI
-encode_md_value( int pubkey_algo, MD_HANDLE md,
-                int hash_algo, unsigned nbits )
+encode_md_value( PKT_public_key *pk, PKT_secret_key *sk,
+                MD_HANDLE md, int hash_algo )
 {
-    int algo = hash_algo? hash_algo : md_get_algo(md);
-    const byte *asn;
-    size_t asnlen, mdlen;
-    MPI frame;
-
-    if( pubkey_algo == PUBKEY_ALGO_DSA ) {
-        mdlen = md_digest_length (hash_algo);
-        if (mdlen != 20) {
-            log_error (_("DSA requires the use of a 160 bit hash algorithm\n"));
-            return NULL;
-        }
+  MPI frame;
+
+  assert(hash_algo);
+  assert(pk || sk);
+
+  if((pk?pk->pubkey_algo:sk->pubkey_algo) == PUBKEY_ALGO_DSA)
+    {
+      /* It's a DSA signature, so find out the size of q. */
+
+      unsigned int qbytes=mpi_get_nbits(pk?pk->pkey[1]:sk->skey[1]);
+
+      /* Make sure it is a multiple of 8 bits. */
 
-       frame = md_is_secure(md)? mpi_alloc_secure((md_digest_length(hash_algo)
-                                +BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB )
-                               : mpi_alloc((md_digest_length(hash_algo)
-                                +BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB );
-       mpi_set_buffer( frame, md_read(md, hash_algo),
-                              md_digest_length(hash_algo), 0 );
+      if(qbytes%8)
+       {
+         log_error(_("DSA requires the hash length to be a"
+                     " multiple of 8 bits\n"));
+         return NULL;
+       }
+
+      /* Don't allow any q smaller than 160 bits.  This might need a
+        revisit as the DSA2 design firms up, but for now, we don't
+        want someone to issue signatures from a key with a 16-bit q
+        or something like that, which would look correct but allow
+        trivial forgeries.  Yes, I know this rules out using MD5 with
+        DSA. ;) */
+
+      if(qbytes<160)
+       {
+         log_error(_("DSA key %s uses an unsafe (%u bit) hash\n"),
+                   pk?keystr_from_pk(pk):keystr_from_sk(sk),qbytes);
+         return NULL;
+       }
+
+      qbytes/=8;
+
+      /* Check if we're too short.  Too long is safe as we'll
+        automatically left-truncate. */
+
+      if(md_digest_length(hash_algo) < qbytes)
+       {
+         log_error(_("DSA key %s requires a %u bit or larger hash\n"),
+                   pk?keystr_from_pk(pk):keystr_from_sk(sk),qbytes*8);
+         return NULL;
+       }
+
+      frame = md_is_secure(md)? mpi_alloc_secure((qbytes+BYTES_PER_MPI_LIMB-1)
+                                                / BYTES_PER_MPI_LIMB )
+       : mpi_alloc((qbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB );
+
+      mpi_set_buffer( frame, md_read(md, hash_algo), qbytes, 0 );
     }
-    else {
-       asn = md_asn_oid( algo, &asnlen, &mdlen );
-       frame = do_encode_md( md, algo, mdlen, nbits, asn, asnlen );
+  else
+    {
+      const byte *asn;
+      size_t asnlen,mdlen;
+
+      asn = md_asn_oid( hash_algo, &asnlen, &mdlen );
+      frame = do_encode_md( md, hash_algo, mdlen,
+                           mpi_get_nbits(pk?pk->pkey[0]:sk->skey[0]),
+                           asn, asnlen );
     }
-    return frame;
+
+  return frame;
 }
index d576769..1570334 100644 (file)
@@ -274,8 +274,7 @@ do_check( PKT_public_key *pk, PKT_signature *sig, MD_HANDLE digest,
     }
     md_final( digest );
 
-    result = encode_md_value( pk->pubkey_algo, digest, sig->digest_algo,
-                             mpi_get_nbits(pk->pkey[0]) );
+    result = encode_md_value( pk, NULL, digest, sig->digest_algo );
     if (!result)
         return G10ERR_GENERAL;
     ctx.sig = sig;
index 79e7567..925fef4 100644 (file)
@@ -319,8 +319,17 @@ do_sign( PKT_secret_key *sk, PKT_signature *sig,
       }
     else 
       {
-        frame = encode_md_value( sk->pubkey_algo, md,
-                                 digest_algo, mpi_get_nbits(sk->skey[0]) );
+       /* TODO: remove this check in the future once all the
+          variable-q DSA stuff makes it into the standard. */
+       if(!opt.expert
+          && sk->pubkey_algo==PUBKEY_ALGO_DSA
+          && md_digest_length(digest_algo)!=20)
+         {
+           log_error(_("DSA requires the use of a 160 bit hash algorithm\n"));
+           return G10ERR_GENERAL;
+         }
+
+        frame = encode_md_value( NULL, sk, md, digest_algo );
         if (!frame)
           return G10ERR_GENERAL;
         rc = pubkey_sign( sk->pubkey_algo, sig->data, frame, sk->skey );
@@ -336,9 +345,7 @@ do_sign( PKT_secret_key *sk, PKT_signature *sig,
         if( get_pubkey( pk, sig->keyid ) )
             rc = G10ERR_NO_PUBKEY;
         else {
-            frame = encode_md_value (pk->pubkey_algo, md,
-                                     sig->digest_algo,
-                                     mpi_get_nbits(pk->pkey[0]) );
+           frame = encode_md_value (pk, NULL, md, sig->digest_algo );
             if (!frame)
                 rc = G10ERR_GENERAL;
             else