* basic.c (verify_one_signature,check_pubkey_sign)
authorWerner Koch <wk@gnupg.org>
Wed, 15 Jan 2003 14:02:01 +0000 (14:02 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 15 Jan 2003 14:02:01 +0000 (14:02 +0000)
(check_pubkey): New.
(main): Check public key functions. Add a --debug option.

* sexp.c (gcry_sexp_length): Fixed.  This was seriously broken.

* pubkey.c (sexp_data_to_mpi): New.  This handles pkcs1 padding.
(gcry_pk_sign, gcry_pk_verify): Use it here.
(gcry_pk_encrypt): And here.
(pubkey_verify): Add debug code.
(sexp_to_enc): Handle flags in the input and return the pkcs1 flag
in a new parameter.
(gcry_pk_decrypt): Prepare for future pkcs1 handling.

NEWS
cipher/ChangeLog
cipher/pubkey.c
libgcrypt.txt
src/ChangeLog
src/gcrypt.h
src/global.c
src/sexp.c
src/testapi.c
tests/ChangeLog
tests/basic.c

diff --git a/NEWS b/NEWS
index 4b13c35..9ace47e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,11 @@
 Noteworthy changes in version 1.1.12 (unreleased)
 -------------------------------------------------
 
+ * gcry_pk_sign, gcry_pk_verify and gcry_pk_encrypt can now handle an
+   optional pkcs1 flags parameter in the S-expression.  A similar flag
+   may be passed to gcry_pk_decrypt byt it is only syntactically
+   implemented.
+
 
 Noteworthy changes in version 1.1.11 (2002-12-21)
 -------------------------------------------------
index 5984915..7745d5c 100644 (file)
@@ -1,3 +1,13 @@
+2003-01-15  Werner Koch  <wk@gnupg.org>
+
+       * pubkey.c (sexp_data_to_mpi): New.  This handles pkcs1 padding.
+       (gcry_pk_sign, gcry_pk_verify): Use it here.
+       (gcry_pk_encrypt): And here.
+       (pubkey_verify): Add debug code.
+       (sexp_to_enc): Handle flags in the input and return the pkcs1 flag
+       in a new parameter.
+       (gcry_pk_decrypt): Prepare for future pkcs1 handling.
+
 2002-12-19  Werner Koch  <wk@gnupg.org>
 
        * random.c (_gcry_random_initialize): New.
index 30e6733..37c4fdb 100644 (file)
@@ -1,5 +1,5 @@
 /* pubkey.c  - pubkey dispatcher
- *     Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 1998,1999,2000,2002,2003 Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -633,6 +633,15 @@ pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
 {
     int i, rc;
 
+    if( DBG_CIPHER ) {
+       log_debug("pubkey_verify: algo=%d\n", algo );
+       for(i=0; i < pubkey_get_npkey(algo); i++ )
+           log_mpidump("  pkey:", pkey[i] );
+       for(i=0; i < pubkey_get_nsig(algo); i++ )
+           log_mpidump("   sig:", data[i] );
+       log_mpidump("  hash:", hash );
+    }
+
     do {
        for(i=0; pubkey_table[i].name; i++ )
            if( pubkey_table[i].algo == algo ) {
@@ -844,9 +853,16 @@ sexp_to_sig( GCRY_SEXP sexp, MPI **retarray, int *retalgo)
 /****************
  * Take sexp and return an array of MPI as used for our internal decrypt
  * function.
+ * s_data = (enc-val
+ *           [(flags [pkcs1])
+ *           (<algo>
+ *             (<param_name1> <mpi>)
+ *             ...
+ *             (<param_namen> <mpi>)
+ *           ))
  */
 static int
-sexp_to_enc( GCRY_SEXP sexp, MPI **retarray, int *retalgo)
+sexp_to_enc( GCRY_SEXP sexp, MPI **retarray, int *retalgo, int *ret_want_pkcs1)
 {
     GCRY_SEXP list, l2;
     const char *name;
@@ -857,28 +873,66 @@ sexp_to_enc( GCRY_SEXP sexp, MPI **retarray, int *retalgo)
     const char *elems;
     GCRY_MPI *array;
 
+    *ret_want_pkcs1 = 0;
     /* check that the first element is valid */
     list = gcry_sexp_find_token( sexp, "enc-val" , 0 );
     if( !list )
        return GCRYERR_INV_OBJ; /* Does not contain a encrypted value object */
-    l2 = gcry_sexp_cadr( list );
-    gcry_sexp_release ( list );
-    list = l2;
-    if( !list ) {
-       gcry_sexp_release ( list );
+    l2 = gcry_sexp_nth (list, 1);
+    if (!l2 ) {
+       gcry_sexp_release (list);
        return GCRYERR_NO_OBJ; /* no cdr for the data object */
     }
-    name = gcry_sexp_nth_data( list, 0, &n );
-    if( !name ) {
-       gcry_sexp_release ( list );
+    name = gcry_sexp_nth_data (l2, 0, &n);
+    if (!name) {
+       gcry_sexp_release (l2);
+       gcry_sexp_release (list);
        return GCRYERR_INV_OBJ; /* invalid structure of object */
     }
+    if ( n == 5 && !memcmp (name, "flags", 5)) {
+      /* There is a flags element - process it */
+      const char *s;
+
+      for (i=gcry_sexp_length (l2)-1; i > 0; i--)
+        {
+          s = gcry_sexp_nth_data (l2, i, &n);
+          if (!s)
+            ; /* not a data element - ignore */
+          else if ( n == 3 && !memcmp (s, "raw", 3))
+            ; /* just a dummy because it is the default */
+          else if ( n == 5 && !memcmp (s, "pkcs1", 5))
+            *ret_want_pkcs1 = 1;
+          else
+            {
+              gcry_sexp_release (l2);
+              gcry_sexp_release (list);
+              return GCRYERR_INV_FLAG;
+            }
+        }
+      
+      /* Get the next which has the actual data */
+      gcry_sexp_release (l2);
+      l2 = gcry_sexp_nth (list, 2);
+      if (!l2 ) {
+       gcry_sexp_release (list);
+       return GCRYERR_NO_OBJ; /* no cdr for the data object */
+      }
+      name = gcry_sexp_nth_data (l2, 0, &n);
+      if (!name) {
+       gcry_sexp_release (l2);
+       gcry_sexp_release (list);
+       return GCRYERR_INV_OBJ; /* invalid structure of object */
+      }
+    }
+    gcry_sexp_release (list);
+    list = l2; l2 = NULL;
+    
     for(i=0; (s=enc_info_table[i].name); i++ ) {
        if( strlen(s) == n && !memcmp( s, name, n ) )
            break;
     }
     if( !s ) {
-       gcry_sexp_release ( list );
+       gcry_sexp_release (list);
        return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
     }
 
@@ -914,30 +968,265 @@ sexp_to_enc( GCRY_SEXP sexp, MPI **retarray, int *retalgo)
     return 0;
 }
 
+/* Take the hash value and convert into an MPI, suitable for for
+   passing to the low level functions.  We currently support the
+   old style way of passing just a MPI and the modern interface which
+   allows to pass flags so that we can choose between raw and pkcs1
+   padding - may be more padding options later. 
+
+   (<mpi>)
+   or
+   (data
+    [(flags [pkcs1])]
+    [(hash <algo> <value>)]
+    [(value <text>)]
+   )
+   
+   Either the VALUE or the HASH element must be present for use
+   with signatures.  VALUE is used for encryption.
+
+   NBITS is the length of the key in bits. 
+
+*/
+static int 
+sexp_data_to_mpi (GcrySexp input, unsigned int nbits, GcryMPI *ret_mpi,
+                  int for_encryption)
+{
+  int rc = 0;
+  GcrySexp ldata, lhash, lvalue;
+  int i;
+  size_t n;
+  const char *s;
+  int is_raw = 0, is_pkcs1 = 0, unknown_flag=0; 
+
+  *ret_mpi = NULL;
+  ldata = gcry_sexp_find_token (input, "data", 0);
+  if (!ldata)
+    { /* assume old style */
+      *ret_mpi = gcry_sexp_nth_mpi (input, 0, 0);
+      return *ret_mpi? 0 : GCRYERR_INV_OBJ;
+    }
+
+  /* see whether there is a flags object */
+  {
+    GcrySexp lflags = gcry_sexp_find_token (ldata, "flags", 0);
+    if (lflags)
+      { /* parse the flags list. */
+        for (i=gcry_sexp_length (lflags)-1; i > 0; i--)
+          {
+            s = gcry_sexp_nth_data (lflags, i, &n);
+            if (!s)
+              ; /* not a data element*/
+            else if ( n == 3 && !memcmp (s, "raw", 3))
+              is_raw = 1;
+            else if ( n == 5 && !memcmp (s, "pkcs1", 5))
+              is_pkcs1 = 1;
+            else
+              unknown_flag = 1;
+          }
+        gcry_sexp_release (lflags);
+      }
+  }
+
+  if (!is_pkcs1 && !is_raw)
+    is_raw = 1; /* default to raw */
+
+  /* Get HASH or MPI */
+  lhash = gcry_sexp_find_token (ldata, "hash", 0);
+  lvalue = lhash? NULL : gcry_sexp_find_token (ldata, "value", 0);
+
+  if (!(!lhash ^ !lvalue))
+    rc = GCRYERR_INV_OBJ; /* none or both given */
+  else if (unknown_flag)
+    rc = GCRYERR_INV_FLAG;
+  else if (is_raw && is_pkcs1 && !for_encryption)
+    rc = GCRYERR_CONFLICT;
+  else if (is_raw && lvalue)
+    {
+      *ret_mpi = gcry_sexp_nth_mpi (lvalue, 1, 0);
+      if (!*ret_mpi)
+        rc = GCRYERR_INV_OBJ;
+    }
+  else if (is_pkcs1 && lvalue && for_encryption)
+    { /* create pkcs#1 block type 2 padding */
+      unsigned char *frame = NULL;
+      size_t nframe = (nbits+7) / 8;
+      const void * value;
+      size_t valuelen;
+      unsigned char *p;
+
+      if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
+        rc = GCRYERR_INV_OBJ;
+      else if (valuelen + 7 > nframe || !nframe)
+        {
+          /* Can't encode a VALUELEN value in a NFRAME bytes frame. */
+          rc = GCRYERR_TOO_SHORT; /* the key is too short */
+        }
+      else if ( !(frame = gcry_malloc_secure (nframe)))
+        rc = GCRYERR_NO_MEM;
+      else
+        {
+          n = 0;
+          frame[n++] = 0;
+          frame[n++] = 2; /* block type */
+          i = nframe - 3 - valuelen;
+          assert (i > 0);
+          p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
+          /* replace zero bytes by new values*/
+          for (;;)
+            {
+              int j, k;
+              unsigned char *pp;
+              
+              /* count the zero bytes */
+              for (j=k=0; j < i; j++)
+                {
+                  if (!p[j])
+                    k++;
+                }
+              if (!k)
+                break; /* okay: no (more) zero bytes */
+              
+              k += k/128; /* better get some more */
+              pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
+              for (j=0; j < i && k; j++)
+                {
+                  if (!p[j])
+                    p[j] = pp[--k];
+                }
+              gcry_free (pp);
+            }
+          memcpy (frame+n, p, i);
+          n += i;
+          gcry_free (p);
+          
+          frame[n++] = 0;
+          memcpy (frame+n, value, valuelen);
+          n += valuelen;
+          assert (n == nframe);
+
+          gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, frame, &nframe);
+        }
+
+      gcry_free(frame);
+    }
+  else if (is_pkcs1 && lhash && !for_encryption)
+    { /* create pkcs#1 block type 1 padding */
+      if (gcry_sexp_length (lhash) != 3)
+        rc = GCRYERR_INV_OBJ;
+      else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
+        rc = GCRYERR_INV_OBJ;
+      else
+        {
+          static struct { const char *name; int algo; } hashnames[] = 
+          { { "sha1",   GCRY_MD_SHA1 },
+            { "md5",    GCRY_MD_MD5 },
+            { "rmd160", GCRY_MD_RMD160 },
+            { "sha256", GCRY_MD_SHA256 },
+            { "sha384", GCRY_MD_SHA384 },
+            { "sha512", GCRY_MD_SHA512 },
+            { "md2",    GCRY_MD_MD2 },
+            { "md4",    GCRY_MD_MD4 },
+            { "tiger",  GCRY_MD_TIGER },
+            { "haval",  GCRY_MD_HAVAL },
+            { NULL }
+          };
+          int algo;
+          byte asn[100];
+          byte *frame = NULL;
+          size_t nframe = (nbits+7) / 8;
+          const void * value;
+          size_t valuelen;
+          size_t asnlen, dlen;
+            
+          for (i=0; hashnames[i].name; i++)
+            {
+              if ( strlen (hashnames[i].name) == n
+                   && !memcmp (hashnames[i].name, s, n))
+                break;
+            }
+
+          algo = hashnames[i].algo;
+          asnlen = DIM(asn);
+          dlen = gcry_md_get_algo_dlen (algo);
+
+          if (!hashnames[i].name)
+            rc = GCRYERR_INV_MD_ALGO;
+          else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen))
+                    || !valuelen )
+            rc = GCRYERR_INV_OBJ;
+          else if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
+            rc = GCRYERR_NOT_IMPL; /* we don't have all of the above algos */
+          else if ( valuelen != dlen )
+            {
+              /* hash value does not match the length of digest for
+                 the given algo */
+              rc = GCRYERR_CONFLICT;
+            }
+          else if( !dlen || dlen + asnlen + 4 > nframe)
+            {
+              /* can't encode an DLEN byte digest MD into a NFRAME byte frame */
+              rc = GCRYERR_TOO_SHORT;
+            }
+          else if ( !(frame = gcry_malloc (nframe)) )
+            rc = GCRYERR_NO_MEM;
+          else
+            { /* assemble the pkcs#1 block type 1 */
+              n = 0;
+              frame[n++] = 0;
+              frame[n++] = 1; /* block type */
+              i = nframe - valuelen - asnlen - 3 ;
+              assert (i > 1);
+              memset (frame+n, 0xff, i );
+              n += i;
+              frame[n++] = 0;
+              memcpy (frame+n, asn, asnlen);
+              n += asnlen;
+              memcpy (frame+n, value, valuelen );
+              n += valuelen;
+              assert (n == nframe);
+      
+              /* convert it into an MPI */
+              gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, frame, &nframe);
+            }
+          
+          gcry_free (frame);
+        }
+    }
+  else
+    rc = GCRYERR_CONFLICT;
+   
+  gcry_sexp_release (ldata);
+  gcry_sexp_release (lhash);
+  gcry_sexp_release (lvalue);
+  return rc;
+}
+
 
-/****************
- * Do a PK encrypt operation
- *
- * Caller has to provide a public key as the SEXP pkey and data as a SEXP
- * with just one MPI in it.  The function returns a a sexp which may
- * be passed to to pk_decrypt.
- * Later versions of this functions may take more complex input data, for 
- * example s_data could have a control tag which allows us to to PKCS-1
- * encoding directly here.
- *
- * Returns: 0 or an errorcode.
- *
- * s_data = (<mpi>)
- * s_pkey = <key-as-defined-in-sexp_to_key>
- * r_ciph = (enc-val
- *           (<algo>
- *             (<param_name1> <mpi>)
- *             ...
- *             (<param_namen> <mpi>)
- *           ))
- */
+/*
+   Do a PK encrypt operation
+  
+   Caller has to provide a public key as the SEXP pkey and data as a
+   SEXP with just one MPI in it. Alternativly S_DATA might be a
+   complex S-Expression, similar to the one used for signature
+   verification.  This provides a flag which allows to handle PKCS#1
+   block type 2 padding.  The function returns a a sexp which may be
+   passed to to pk_decrypt.
+  
+   Returns: 0 or an errorcode.
+  
+   s_data = See comment for sexp_data_to_mpi
+   s_pkey = <key-as-defined-in-sexp_to_key>
+   r_ciph = (enc-val
+               (<algo>
+                 (<param_name1> <mpi>)
+                 ...
+                 (<param_namen> <mpi>)
+               ))
+
+*/
 int
-gcry_pk_encrypt( GCRY_SEXP *r_ciph, GCRY_SEXP s_data, GCRY_SEXP s_pkey )
+gcry_pk_encrypt (GCRY_SEXP *r_ciph, GCRY_SEXP s_data, GCRY_SEXP s_pkey)
 {
     MPI *pkey, data, *ciph;
     const char *key_algo_name, *algo_name, *algo_elems;
@@ -970,8 +1259,8 @@ gcry_pk_encrypt( GCRY_SEXP *r_ciph, GCRY_SEXP s_data, GCRY_SEXP s_pkey )
     algo_elems = enc_info_table[i].elements;
 
     /* get the stuff we want to encrypt */
-    data = gcry_sexp_nth_mpi( s_data, 0, 0 );
-    if( !data ) {
+    rc = sexp_data_to_mpi (s_data, gcry_pk_get_nbits (s_pkey), &data, 1);
+    if (rc) {
        release_mpi_array( pkey );
         gcry_free (pkey);
        return GCRYERR_INV_OBJ;
@@ -1065,13 +1354,13 @@ int
 gcry_pk_decrypt( GCRY_SEXP *r_plain, GCRY_SEXP s_data, GCRY_SEXP s_skey )
 {
     MPI *skey, *data, plain;
-    int rc, algo, dataalgo;
+    int rc, algo, dataalgo, want_pkcs1;
 
     rc = sexp_to_key( s_skey, 1, &skey, &algo, NULL );
     if( rc ) {
        return rc;
     }
-    rc = sexp_to_enc( s_data, &data, &dataalgo );
+    rc = sexp_to_enc( s_data, &data, &dataalgo, &want_pkcs1 );
     if( rc ) {
        release_mpi_array( skey );
         gcry_free (skey);
@@ -1110,10 +1399,12 @@ gcry_pk_decrypt( GCRY_SEXP *r_plain, GCRY_SEXP s_data, GCRY_SEXP s_skey )
 /****************
  * Create a signature.
  *
- * Caller has to provide a secret key as the SEXP skey and data expressed
- * as a SEXP list hash with only one element which should instantly be
- * available as a MPI. Later versions of this functions may provide padding
- * and other things depending on data.
+ * Caller has to provide a secret key as the SEXP skey and data
+ * expressed as a SEXP list hash with only one element which should
+ * instantly be available as a MPI. Alternatively the structure given
+ * below may be used for S_HASH, it provides the abiliy to pass flags
+ * to the operation; the only flag defined by now is "pkcs1" which
+ * does PKCS#1 block type 1 style padding.
  *
  * Returns: 0 or an errorcode.
  *         In case of 0 the function returns a new SEXP with the
@@ -1121,15 +1412,15 @@ gcry_pk_decrypt( GCRY_SEXP *r_plain, GCRY_SEXP s_data, GCRY_SEXP s_skey )
  *         other arguments but is always suitable to be passed to
  *         gcry_pk_verify
  *
- * s_hash = (<mpi>)
+ * s_hash = See comment for sexp_data_to_mpi
+ *             
  * s_skey = <key-as-defined-in-sexp_to_key>
  * r_sig  = (sig-val
  *           (<algo>
  *             (<param_name1> <mpi>)
  *             ...
  *             (<param_namen> <mpi>)
- *           ))
- */
+ * )) */
 int
 gcry_pk_sign( GCRY_SEXP *r_sig, GCRY_SEXP s_hash, GCRY_SEXP s_skey )
 {
@@ -1160,11 +1451,12 @@ gcry_pk_sign( GCRY_SEXP *r_sig, GCRY_SEXP s_hash, GCRY_SEXP s_skey )
     algo_elems = sig_info_table[i].elements;
 
     /* get the stuff we want to sign */
-    hash = gcry_sexp_nth_mpi( s_hash, 0, 0 );
-    if( !hash ) {
+    /* Note that pk_get_nbits does also work on a private key */
+    rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_skey), &hash, 0);
+    if (rc) {
        release_mpi_array( skey );
         gcry_free (skey);
-       return -1; /* fixme: get a real errorcode for this */
+       return rc; 
     }
     result = gcry_xcalloc( (strlen(algo_elems)+1) , sizeof *result );
     rc = pubkey_sign( algo, result, hash, skey );
@@ -1258,8 +1550,8 @@ gcry_pk_verify( GCRY_SEXP s_sig, GCRY_SEXP s_hash, GCRY_SEXP s_pkey )
        return -1; /* fixme: add real errornumber - algo does not match */
     }
 
-    hash = gcry_sexp_nth_mpi( s_hash, 0, 0 );
-    if( !hash ) {
+    rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_pkey), &hash, 0);
+    if (rc) {
        release_mpi_array( pkey );
         gcry_free (pkey);
        release_mpi_array( sig );
index 025391b..620b0d2 100644 (file)
@@ -1,11 +1,19 @@
 %%comments:
-Copyright (C) 2001 Free Software Foundation, Inc.
-
-Permission is granted to copy, distribute and/or modify this document
-under the terms of the GNU Free Documentation License, Version 1.1 or
-any later version published by the Free Software Foundation; with no
-Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
-Texts. A copy of the license is included in the file COPYING.
+<p>
+The copyright licensing notice below applies to this text.  The software
+described in this text has its own copyright notice and license, which can
+usually be found in the distribution itself.
+</p>
+<p>
+Copyright &copy; 2000, 2001, 2002 Free Software Foundation, Inc.
+</p>
+<p>
+Permission is granted to copy, distribute, and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or any
+later version published by the Free Software Foundation; with no Invariant
+Sections, with no Front-Cover Texts, and with no Back-Cover Texts.  A copy
+of this license is included in the file <a href="COPYING.DOC">COPYING.DOC</a>.
+</p>
 
 %%name: Libgcrypt
 
@@ -14,51 +22,59 @@ Texts. A copy of the license is included in the file COPYING.
 %%full-description: This is a general purpose cryptographic library
 based on the code from GnuPG.  It provides functions for all
 cryptograhic building blocks: symmetric ciphers
-(AES,DES,Blowfish,CAST5,Twofish,Arcfour), hash algorithms (MD5,
+(AES,DES,Blowfish,CAST5,Twofish,Arcfour), hash algorithms (MD4, MD5,
 RIPE-MD160, SHA-1, TIGER-192), MACs (HMAC for all hash algorithms),
 public key algorithms (RSA, ElGamal, DSA), large integer functions,
 random numbers and a lot of supporting functions.
 
-%%category: security, libraries
+%%category: sec, libs
 
 %%license: LGPL
-%%license verified by: 
-%%license verified on: 
 
-%%maintainer: g10 Code GmbH <wk@g10code.com>
+%%license-verified-by: Janet Casey <jcasey@gnu.org>
+
+%%license-verified-on: 2001-04-23
+
+%%maintainer: Werner Koch <libgcrypt@g10code.com>
 
-%%updated: 2001-06-01
+%%updated: 2002-12-23
 
-%%keywords: encryption, public key, digital signature, hash
+%%keywords: encryption, public key, digital signature, hash, libgcrypt
 
-%%interface:
+%%interface: Command line
 
 %%programs: 
 
-%%GNU: (I am not sure - it is a spring-off from GnuPG)
+%%GNU: yes
 
 %%web-page: http://www.gnupg.org
 
-%%support: paid extension/consulting from http://www.g10code.com
+%%support: Paid extension/consulting from http://www.g10code.com
 
-%%doc: English programmer reference in Texinfo, Postscript, HTML included
+%%doc: Programmer reference in Texinfo, Postscript, HTML included
 
 %%developers:  Matthew Skala, Michael Roth, Niklas Hernaeus, Remi
-Guyomarch, Werner Koch <wk@gnupg.org>.
+Guyomarch, Simon Josefsson, Werner Koch <wk@gnupg.org>.
 
 %%contributors: 
 
 %%sponsors: 
 
-%%source: ftp://ftp.gnupg.org/gcrypt/alpha/libgcrypt/
+%%source-tarball: ftp://ftp.gnupg.org/gcrypt/alpha/libgcrypt/libgcrypt-1.1.11.tar.gz
+
+%%source-info:
+
+%%source-template:
 
 %%debian:
 
-%%redhat:
+%%rpm: 
 
 %%repository:  See http://www.gnupg.org/cvs-access.html
 
-%%related: 
+%%related:   
+
+%%related-outside-directory: 
 
 %%source-language: C
 
@@ -72,9 +88,10 @@ Guyomarch, Werner Koch <wk@gnupg.org>.
 
 %%source-prerequisites:
 
-%%version: 1.1.3 alpha released on 2001-05-31
+%%version: 1.1.11 released 2002-12-21
 
-%%announce-list: announce@gnupg.org  announce-request@gnupg.org
+%%announce-list: <gnupg-announce@gnupg.org>  
+                <gnupg-announce-request@gnupg.org>
 
 %%announce-news:
 
@@ -82,7 +99,12 @@ Guyomarch, Werner Koch <wk@gnupg.org>.
 
 %%help-news:
 
-%%dev-list: gcrypt-devel@gnupg.org  gcrypt-devel-request@gnupg.org
+%%help-irc-channel:
+
+%%dev-irc-channel:
+
+%%dev-list: <gcrypt-devel@gnupg.org>  
+           <gcrypt-devel-request@gnupg.org>
 
 %%dev-news:
 
@@ -90,4 +112,7 @@ Guyomarch, Werner Koch <wk@gnupg.org>.
 
 %%bug-database: 
 
-%%entry written by: Werner Koch <wk@gnupg.org>
\ No newline at end of file
+%%entry-written-by: Werner Koch <wk@gnupg.org>
+
+%%entry-added: 2001-06-01
+
index 9d5fbed..f7b918d 100644 (file)
@@ -1,3 +1,11 @@
+2003-01-15  Werner Koch  <wk@gnupg.org>
+
+       * sexp.c (gcry_sexp_length): Fixed.  This was seriously broken.
+
+2003-01-14  Werner Koch  <wk@gnupg.org>
+
+       * gcrypt.h (GCRYERR_INV_FLAG), global.c (gcry_strerror): New.
+
 2003-01-02  Werner Koch  <wk@gnupg.org>
 
        * libgcrypt.vers: Temporary export _gcry_generate_elg_prime for
index b4f046d..adb76e0 100644 (file)
@@ -37,7 +37,7 @@ extern "C" {
    autoconf (using the AM_PATH_GCRYPT macro) check that this header
    matches the installed library.  Note: Do not edit the next line as
    configure may fix the string here.  */
-#define GCRYPT_VERSION "1.1.11"
+#define GCRYPT_VERSION "1.1.12-cvs"
 
 /* Internal: We can't use the convenience macros for the multi
    precision integer functions when building this library. */
@@ -99,12 +99,13 @@ enum
     GCRYERR_INTERNAL = 63,        /* internal error */
     GCRYERR_EOF = 64,            /* (-1) is remapped to this value */
     GCRYERR_INV_OBJ = 65,         /* an object is not valid */
-    GCRYERR_TOO_SHORT = 66,       /* provided buffer too short */
+    GCRYERR_TOO_SHORT = 66,       /* provided buffer/object too short */
     GCRYERR_TOO_LARGE = 67,       /* object is too large */
     GCRYERR_NO_OBJ = 68,          /* Missing item in an object */
     GCRYERR_NOT_IMPL = 69,        /* Not implemented */
     GCRYERR_CONFLICT = 70,        /* conflicting use of functions/values */
     GCRYERR_INV_CIPHER_MODE = 71, /* invalid/unsupported cipher mode */ 
+    GCRYERR_INV_FLAG = 72,        /* invalid flag */
 
     /* error codes pertaining to S-expressions */
     GCRYERR_SEXP_INV_LEN_SPEC    = 201,
index 8c1bc25..90694d0 100644 (file)
@@ -298,6 +298,7 @@ gcry_strerror( int ec )
       X(NOT_IMPL,       N_("not implemented"))
       X(CONFLICT,      N_("conflict"))
       X(INV_CIPHER_MODE,N_("invalid cipher mode"))
+        X(INV_FLAG,     N_("invalid flag"))
 
         X(SEXP_INV_LEN_SPEC   ,N_("invalid length specification")) 
         X(SEXP_STRING_TOO_LONG,N_("string too long")) 
index aea3a5f..bda2484 100644 (file)
@@ -383,7 +383,7 @@ gcry_sexp_find_token( const GCRY_SEXP list, const char *tok, size_t toklen )
 }
 
 /****************
- * return the length of the given list
+ * Return the length of the given list
  */
 int
 gcry_sexp_length( const GCRY_SEXP list )
@@ -401,14 +401,13 @@ gcry_sexp_length( const GCRY_SEXP list )
     while ( (type=*p) != ST_STOP ) {
        p++;
        if ( type == ST_DATA ) {
-           memcpy ( &n, ++p, sizeof n );
+           memcpy ( &n, p, sizeof n );
            p += sizeof n + n;
-           p--;
-           if ( !level )
+           if ( level == 1 )
                length++;
        }
        else if ( type == ST_OPEN ) {
-           if ( !level )
+           if ( level == 1 )
                length++;
            level++;
        }
index a9b724f..0dde34c 100644 (file)
@@ -110,4 +110,3 @@ main( int argc, char **argv )
 
     return 0;
 }
-
index eac4c61..d25fbae 100644 (file)
@@ -1,3 +1,9 @@
+2003-01-15  Werner Koch  <wk@gnupg.org>
+
+       * basic.c (verify_one_signature,check_pubkey_sign)
+       (check_pubkey): New.
+       (main): Check public key functions. Add a --debug option.
+
 2002-11-23  Werner Koch  <wk@gnupg.org>
 
        * basic.c (check_digests): Add another test for MD4.  By Simon
index 010ca27..cbe9517 100644 (file)
 #include <stdarg.h>
 #include "../src/gcrypt.h"
 
+
+static const char sample_private_key_1[] =
+"(private-key\n"
+" (rsa\n"
+"  (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa"
+      "2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291"
+      "ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7"
+      "891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)\n"
+"  (e #010001#)\n"
+"  (d #046129F2489D71579BE0A75FE029BD6CDB574EBF57EA8A5B0FDA942CAB943B11"
+      "7D7BB95E5D28875E0F9FC5FCC06A72F6D502464DABDED78EF6B716177B83D5BD"
+      "C543DC5D3FED932E59F5897E92E6F58A0F33424106A3B6FA2CBF877510E4AC21"
+      "C3EE47851E97D12996222AC3566D4CCB0B83D164074ABF7DE655FC2446DA1781#)\n"
+"  (p #00e861b700e17e8afe6837e7512e35b6ca11d0ae47d8b85161c67baf64377213"
+      "fe52d772f2035b3ca830af41d8a4120e1c1c70d12cc22f00d28d31dd48a8d424f1#)\n"
+"  (q #00f7a7ca5367c661f8e62df34f0d05c10c88e5492348dd7bddc942c9a8f369f9"
+      "35a07785d2db805215ed786e4285df1658eed3ce84f469b81b50d358407b4ad361#)\n"
+"  (u #304559a9ead56d2309d203811a641bb1a09626bc8eb36fffa23c968ec5bd891e"
+      "ebbafc73ae666e01ba7c8990bae06cc2bbe10b75e69fcacb353a6473079d8e9b#)\n"
+" )\n"
+")\n";
+static const char sample_public_key_1[] =
+"(public-key\n"
+" (rsa\n"
+"  (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa"
+      "2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291"
+      "ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7"
+      "891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)\n"
+"  (e #010001#)\n"
+" )\n"
+")\n";
+
+
+
+
+
 static int verbose;
 static int error_count;
 
@@ -365,19 +401,139 @@ check_digests ()
   /* TODO: test HMAC mode */
 }
 
+/* Check that the signature SIG matches the hash HASH. PKEY is the
+   public key used for the verification. BADHASH is a hasvalue which
+   should; result in a bad signature status. */
+static void
+verify_one_signature (GcrySexp pkey, GcrySexp hash,
+                      GcrySexp badhash, GcrySexp sig)
+{
+  int rc;
+
+  rc = gcry_pk_verify (sig, hash, pkey);
+  if (rc)
+    fail ("gcry_pk_verify failed: %s\n", gcry_strerror (rc));
+  rc = gcry_pk_verify (sig, badhash, pkey);
+  if (rc != GCRYERR_BAD_SIGNATURE)
+    fail ("gcry_pk_verify failed to detect a bad signature: %s\n",
+          gcry_strerror (rc));
+}
+
+
+/* Test the public key sign function using the private ket SKEY. PKEY
+   is used for verification. */
+static void
+check_pubkey_sign (GcrySexp skey, GcrySexp pkey)
+{
+  int rc;
+  GcrySexp sig, badhash, hash;
+  int dataidx;
+  static const char baddata[] =
+    "(data\n (flags pkcs1)\n"
+    " (hash sha1 #11223344556677889900AABBCCDDEEFF10203041#))\n";
+  static struct { const char *data; int expected_rc; } datas[] = {
+    { "(data\n (flags pkcs1)\n"
+      " (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
+      0 },
+    { "(data\n (flags )\n"
+      " (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
+      GCRYERR_CONFLICT },
+
+    { "(data\n (flags pkcs1)\n"
+      " (hash foo #11223344556677889900AABBCCDDEEFF10203040#))\n",
+      GCRYERR_INV_MD_ALGO },
+
+    { "(data\n (flags )\n"
+      " (value #11223344556677889900AA#))\n",
+      0 },
+
+    { "(data\n (flags raw)\n"
+      " (value #11223344556677889900AA#))\n",
+      0 },
+
+    { "(data\n (flags pkcs1)\n"
+      " (value #11223344556677889900AA#))\n",
+      GCRYERR_CONFLICT },
+
+    { "(data\n (flags raw foo)\n"
+      " (value #11223344556677889900AA#))\n",
+      GCRYERR_INV_FLAG },
+    
+    { NULL }
+  };
+
+  rc = gcry_sexp_sscan (&badhash, NULL, baddata, strlen (baddata));
+  if (rc)
+      die ("converting data failed: %s\n", gcry_strerror (rc));
+      
+  for (dataidx=0; datas[dataidx].data; dataidx++)
+    {
+      if (verbose)
+        fprintf (stderr, "signature test %d\n", dataidx);
+
+      rc = gcry_sexp_sscan (&hash, NULL, datas[dataidx].data,
+                            strlen (datas[dataidx].data));
+      if (rc)
+        die ("converting data failed: %s\n", gcry_strerror (rc));
+  
+      rc = gcry_pk_sign (&sig, hash, skey);
+      if (rc != datas[dataidx].expected_rc)
+        fail ("gcry_pk_sign failed: %s\n", gcry_strerror (rc));
+      
+      if (!rc)
+        verify_one_signature (pkey, hash, badhash, sig);
+
+      gcry_sexp_release (sig); sig= NULL;
+      gcry_sexp_release (hash); hash= NULL;
+    }
+
+  gcry_sexp_release (badhash);
+}
+
+/* Run all tests for the public key fucntions. */
+static void
+check_pubkey (void)
+{
+  int rc;
+  GcrySexp skey, pkey;
+  
+  rc = gcry_sexp_sscan (&skey, NULL, sample_private_key_1,
+                        strlen (sample_private_key_1));
+  if (!rc)
+    rc = gcry_sexp_sscan (&pkey, NULL, sample_public_key_1,
+                          strlen (sample_public_key_1));
+  if (rc)
+    die ("converting sample key failed: %s\n", gcry_strerror (rc));
+
+  check_pubkey_sign (skey, pkey);
+
+  gcry_sexp_release (skey);
+  gcry_sexp_release (pkey);
+}
+
+
 
 int
 main (int argc, char **argv)
 {
+  int debug = 0;
+
   if (argc > 1 && !strcmp (argv[1], "--verbose"))
     verbose = 1;
+  else if (argc > 1 && !strcmp (argv[1], "--debug"))
+    verbose = debug = 1;
 
-  /*gcry_control (GCRYCTL_DISABLE_INTERNAL_LOCKING, NULL, 0);*/
+  /*gcry_control (GCRYCTL_DISABLE_INTERNAL_LOCKING,0);*/
+  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
   if (!gcry_check_version (GCRYPT_VERSION))
     die ("version mismatch\n");
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+  if (debug)
+    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
   check_ciphers ();
   check_aes128_cbc_cts_cipher ();
   check_digests ();
+  check_pubkey ();
   
   return error_count? 1:0;
 }