summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2003-01-15 14:02:01 +0000
committerWerner Koch <wk@gnupg.org>2003-01-15 14:02:01 +0000
commitb72cee46eea13d6f8c9a47703693c809c2f0c65d (patch)
tree5dafc9d845fedeb45e8ffe64c7cc344af3cd7450
parent6fb130c964f71e34d6c62d0befc11c31c40075ea (diff)
downloadlibgcrypt-b72cee46eea13d6f8c9a47703693c809c2f0c65d.tar.gz
* basic.c (verify_one_signature,check_pubkey_sign)
(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.
-rw-r--r--NEWS5
-rw-r--r--cipher/ChangeLog10
-rw-r--r--cipher/pubkey.c390
-rw-r--r--libgcrypt.txt77
-rw-r--r--src/ChangeLog8
-rw-r--r--src/gcrypt.h5
-rw-r--r--src/global.c1
-rw-r--r--src/sexp.c9
-rw-r--r--src/testapi.c1
-rw-r--r--tests/ChangeLog6
-rw-r--r--tests/basic.c158
11 files changed, 586 insertions, 84 deletions
diff --git a/NEWS b/NEWS
index 4b13c35b..9ace47e7 100644
--- 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)
-------------------------------------------------
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index 5984915e..7745d5c2 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -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.
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 30e6733e..37c4fdb7 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -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 );
diff --git a/libgcrypt.txt b/libgcrypt.txt
index 025391b3..620b0d27 100644
--- a/libgcrypt.txt
+++ b/libgcrypt.txt
@@ -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
+
diff --git a/src/ChangeLog b/src/ChangeLog
index 9d5fbed4..f7b918db 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -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
diff --git a/src/gcrypt.h b/src/gcrypt.h
index b4f046d5..adb76e03 100644
--- a/src/gcrypt.h
+++ b/src/gcrypt.h
@@ -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,
diff --git a/src/global.c b/src/global.c
index 8c1bc25e..90694d08 100644
--- a/src/global.c
+++ b/src/global.c
@@ -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"))
diff --git a/src/sexp.c b/src/sexp.c
index aea3a5fa..bda2484f 100644
--- a/src/sexp.c
+++ b/src/sexp.c
@@ -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++;
}
diff --git a/src/testapi.c b/src/testapi.c
index a9b724f3..0dde34c2 100644
--- a/src/testapi.c
+++ b/src/testapi.c
@@ -110,4 +110,3 @@ main( int argc, char **argv )
return 0;
}
-
diff --git a/tests/ChangeLog b/tests/ChangeLog
index eac4c61b..d25fbae6 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -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
diff --git a/tests/basic.c b/tests/basic.c
index 010ca276..cbe9517f 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -24,6 +24,42 @@
#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;
}