diff options
author | Werner Koch <wk@gnupg.org> | 2003-01-15 14:02:01 +0000 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2003-01-15 14:02:01 +0000 |
commit | b72cee46eea13d6f8c9a47703693c809c2f0c65d (patch) | |
tree | 5dafc9d845fedeb45e8ffe64c7cc344af3cd7450 | |
parent | 6fb130c964f71e34d6c62d0befc11c31c40075ea (diff) | |
download | libgcrypt-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-- | NEWS | 5 | ||||
-rw-r--r-- | cipher/ChangeLog | 10 | ||||
-rw-r--r-- | cipher/pubkey.c | 390 | ||||
-rw-r--r-- | libgcrypt.txt | 77 | ||||
-rw-r--r-- | src/ChangeLog | 8 | ||||
-rw-r--r-- | src/gcrypt.h | 5 | ||||
-rw-r--r-- | src/global.c | 1 | ||||
-rw-r--r-- | src/sexp.c | 9 | ||||
-rw-r--r-- | src/testapi.c | 1 | ||||
-rw-r--r-- | tests/ChangeLog | 6 | ||||
-rw-r--r-- | tests/basic.c | 158 |
11 files changed, 586 insertions, 84 deletions
@@ -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 © 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")) @@ -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; } |