diff options
Diffstat (limited to 'plugins/MirOTR/Libgcrypt/cipher/dsa.c')
-rw-r--r-- | plugins/MirOTR/Libgcrypt/cipher/dsa.c | 997 |
1 files changed, 557 insertions, 440 deletions
diff --git a/plugins/MirOTR/Libgcrypt/cipher/dsa.c b/plugins/MirOTR/Libgcrypt/cipher/dsa.c index ceb94965c5..09cd9693ec 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/dsa.c +++ b/plugins/MirOTR/Libgcrypt/cipher/dsa.c @@ -1,6 +1,7 @@ /* dsa.c - DSA signature algorithm * Copyright (C) 1998, 2000, 2001, 2002, 2003, * 2006, 2008 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH. * * This file is part of Libgcrypt. * @@ -26,6 +27,8 @@ #include "g10lib.h" #include "mpi.h" #include "cipher.h" +#include "pubkey-internal.h" + typedef struct { @@ -55,6 +58,14 @@ typedef struct } dsa_domain_t; +static const char *dsa_names[] = + { + "dsa", + "openpgp-dsa", + NULL, + }; + + /* A sample 1024 bit DSA key used for the selftests. */ static const char sample_secret_key[] = "(private-key" @@ -74,7 +85,7 @@ static const char sample_secret_key[] = " 42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB#)" " (x #11D54E4ADBD3034160F2CED4B7CD292A4EBF3EC0#)))"; /* A sample 1024 bit DSA key used for the selftests (public only). */ -static const char sample_public_key[] = +static const char sample_public_key[] = "(public-key" " (dsa" " (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB" @@ -94,7 +105,6 @@ static const char sample_public_key[] = -static gcry_mpi_t gen_k (gcry_mpi_t q); static int test_keys (DSA_secret_key *sk, unsigned int qbits); static int check_secret_key (DSA_secret_key *sk); static gpg_err_code_t generate (DSA_secret_key *sk, @@ -103,10 +113,12 @@ static gpg_err_code_t generate (DSA_secret_key *sk, int transient_key, dsa_domain_t *domain, gcry_mpi_t **ret_factors); -static void sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, - DSA_secret_key *skey); -static int verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, +static gpg_err_code_t sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, + DSA_secret_key *skey, int flags, int hashalgo); +static gpg_err_code_t verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_public_key *pkey); +static unsigned int dsa_get_nbits (gcry_sexp_t parms); + static void (*progress_cb) (void *,const char *, int, int, int ); static void *progress_cb_data; @@ -130,78 +142,15 @@ progress (int c) } -/* - * Generate a random secret exponent k less than q. - */ -static gcry_mpi_t -gen_k( gcry_mpi_t q ) -{ - gcry_mpi_t k = mpi_alloc_secure( mpi_get_nlimbs(q) ); - unsigned int nbits = mpi_get_nbits(q); - unsigned int nbytes = (nbits+7)/8; - char *rndbuf = NULL; - - if ( DBG_CIPHER ) - log_debug("choosing a random k "); - for (;;) - { - if( DBG_CIPHER ) - progress('.'); - - if ( !rndbuf || nbits < 32 ) - { - gcry_free(rndbuf); - rndbuf = gcry_random_bytes_secure( (nbits+7)/8, GCRY_STRONG_RANDOM ); - } - else - { /* Change only some of the higher bits. We could improve - this by directly requesting more memory at the first call - to get_random_bytes() and use this the here maybe it is - easier to do this directly in random.c. */ - char *pp = gcry_random_bytes_secure( 4, GCRY_STRONG_RANDOM ); - memcpy( rndbuf,pp, 4 ); - gcry_free(pp); - } - _gcry_mpi_set_buffer( k, rndbuf, nbytes, 0 ); - if ( mpi_test_bit( k, nbits-1 ) ) - mpi_set_highbit( k, nbits-1 ); - else - { - mpi_set_highbit( k, nbits-1 ); - mpi_clear_bit( k, nbits-1 ); - } - - if( !(mpi_cmp( k, q ) < 0) ) /* check: k < q */ - { - if( DBG_CIPHER ) - progress('+'); - continue; /* no */ - } - if( !(mpi_cmp_ui( k, 0 ) > 0) ) /* check: k > 0 */ - { - if( DBG_CIPHER ) - progress('-'); - continue; /* no */ - } - break; /* okay */ - } - gcry_free(rndbuf); - if( DBG_CIPHER ) - progress('\n'); - - return k; -} - - /* Check that a freshly generated key actually works. Returns 0 on success. */ static int test_keys (DSA_secret_key *sk, unsigned int qbits) { int result = -1; /* Default to failure. */ DSA_public_key pk; - gcry_mpi_t data = gcry_mpi_new (qbits); - gcry_mpi_t sig_a = gcry_mpi_new (qbits); - gcry_mpi_t sig_b = gcry_mpi_new (qbits); + gcry_mpi_t data = mpi_new (qbits); + gcry_mpi_t sig_a = mpi_new (qbits); + gcry_mpi_t sig_b = mpi_new (qbits); /* Put the relevant parameters into a public key structure. */ pk.p = sk->p; @@ -210,26 +159,26 @@ test_keys (DSA_secret_key *sk, unsigned int qbits) pk.y = sk->y; /* Create a random plaintext. */ - gcry_mpi_randomize (data, qbits, GCRY_WEAK_RANDOM); + _gcry_mpi_randomize (data, qbits, GCRY_WEAK_RANDOM); /* Sign DATA using the secret key. */ - sign (sig_a, sig_b, data, sk); + sign (sig_a, sig_b, data, sk, 0, 0); /* Verify the signature using the public key. */ - if ( !verify (sig_a, sig_b, data, &pk) ) + if ( verify (sig_a, sig_b, data, &pk) ) goto leave; /* Signature does not match. */ /* Modify the data and check that the signing fails. */ - gcry_mpi_add_ui (data, data, 1); - if ( verify (sig_a, sig_b, data, &pk) ) + mpi_add_ui (data, data, 1); + if ( !verify (sig_a, sig_b, data, &pk) ) goto leave; /* Signature matches but should not. */ result = 0; /* The test succeeded. */ leave: - gcry_mpi_release (sig_b); - gcry_mpi_release (sig_a); - gcry_mpi_release (data); + _gcry_mpi_release (sig_b); + _gcry_mpi_release (sig_a); + _gcry_mpi_release (data); return result; } @@ -247,6 +196,7 @@ static gpg_err_code_t generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, int transient_key, dsa_domain_t *domain, gcry_mpi_t **ret_factors ) { + gpg_err_code_t rc; gcry_mpi_t p; /* the prime */ gcry_mpi_t q; /* the 160 bit prime factor */ gcry_mpi_t g; /* the generator */ @@ -298,7 +248,10 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, else { /* Generate new domain parameters. */ - p = _gcry_generate_elg_prime (1, nbits, qbits, NULL, ret_factors); + rc = _gcry_generate_elg_prime (1, nbits, qbits, NULL, &p, ret_factors); + if (rc) + return rc; + /* Get q out of factors. */ q = mpi_copy ((*ret_factors)[0]); gcry_assert (mpi_get_nbits (q) == qbits); @@ -314,48 +267,55 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, { mpi_add_ui (h, h, 1); /* g = h^e mod p */ - gcry_mpi_powm (g, h, e, p); - } + mpi_powm (g, h, e, p); + } while (!mpi_cmp_ui (g, 1)); /* Continue until g != 1. */ } /* Select a random number X with the property: * 0 < x < q-1 + * + * FIXME: Why do we use the requirement x < q-1 ? It should be + * sufficient to test for x < q. FIPS-186-3 check x < q-1 but it + * does not check for 0 < x because it makes sure that Q is unsigned + * and finally adds one to the result so that 0 will never be + * returned. We should replace the code below with _gcry_dsa_gen_k. + * * This must be a very good random number because this is the secret * part. The random quality depends on the transient_key flag. */ random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM; if (DBG_CIPHER) - log_debug("choosing a random x%s", transient_key? " (transient-key)":""); + log_debug("choosing a random x%s\n", transient_key? " (transient-key)":""); gcry_assert( qbits >= 160 ); x = mpi_alloc_secure( mpi_get_nlimbs(q) ); mpi_sub_ui( h, q, 1 ); /* put q-1 into h */ rndbuf = NULL; - do + do { if( DBG_CIPHER ) progress('.'); if( !rndbuf ) - rndbuf = gcry_random_bytes_secure ((qbits+7)/8, random_level); - else + rndbuf = _gcry_random_bytes_secure ((qbits+7)/8, random_level); + else { /* Change only some of the higher bits (= 2 bytes)*/ - char *r = gcry_random_bytes_secure (2, random_level); + char *r = _gcry_random_bytes_secure (2, random_level); memcpy(rndbuf, r, 2 ); - gcry_free(r); + xfree(r); } _gcry_mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 ); mpi_clear_highbit( x, qbits+1 ); - } + } while ( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) ); - gcry_free(rndbuf); + xfree(rndbuf); mpi_free( e ); mpi_free( h ); /* y = g^x mod p */ y = mpi_alloc( mpi_get_nlimbs(p) ); - gcry_mpi_powm( y, g, x, p ); + mpi_powm (y, g, x, p); - if( DBG_CIPHER ) + if( DBG_CIPHER ) { progress('\n'); log_mpidump("dsa p", p ); @@ -375,11 +335,11 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, /* Now we can test our keys (this should never fail!). */ if ( test_keys (sk, qbits) ) { - gcry_mpi_release (sk->p); sk->p = NULL; - gcry_mpi_release (sk->q); sk->q = NULL; - gcry_mpi_release (sk->g); sk->g = NULL; - gcry_mpi_release (sk->y); sk->y = NULL; - gcry_mpi_release (sk->x); sk->x = NULL; + _gcry_mpi_release (sk->p); sk->p = NULL; + _gcry_mpi_release (sk->q); sk->q = NULL; + _gcry_mpi_release (sk->g); sk->g = NULL; + _gcry_mpi_release (sk->y); sk->y = NULL; + _gcry_mpi_release (sk->x); sk->x = NULL; fips_signal_error ("self-test after key generation failed"); return GPG_ERR_SELFTEST_FAILED; } @@ -406,8 +366,8 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, const void *seed; size_t seedlen; } initial_seed = { NULL, NULL, 0 }; - gcry_mpi_t prime_q = NULL; - gcry_mpi_t prime_p = NULL; + gcry_mpi_t prime_q = NULL; + gcry_mpi_t prime_p = NULL; gcry_mpi_t value_g = NULL; /* The generator. */ gcry_mpi_t value_y = NULL; /* g^x mod p */ gcry_mpi_t value_x = NULL; /* The secret exponent. */ @@ -462,20 +422,20 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, /* Get an initial seed value. */ if (deriveparms) { - initial_seed.sexp = gcry_sexp_find_token (deriveparms, "seed", 0); + initial_seed.sexp = sexp_find_token (deriveparms, "seed", 0); if (initial_seed.sexp) - initial_seed.seed = gcry_sexp_nth_data (initial_seed.sexp, 1, + initial_seed.seed = sexp_nth_data (initial_seed.sexp, 1, &initial_seed.seedlen); } - + /* Fixme: Enable 186-3 after it has been approved and after fixing the generation function. */ /* if (use_fips186_2) */ (void)use_fips186_2; - ec = _gcry_generate_fips186_2_prime (nbits, qbits, - initial_seed.seed, + ec = _gcry_generate_fips186_2_prime (nbits, qbits, + initial_seed.seed, initial_seed.seedlen, - &prime_q, &prime_p, + &prime_q, &prime_p, r_counter, r_seed, r_seedlen); /* else */ @@ -483,7 +443,7 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, /* &prime_q, &prime_p, */ /* r_counter, */ /* r_seed, r_seedlen, NULL); */ - gcry_sexp_release (initial_seed.sexp); + sexp_release (initial_seed.sexp); if (ec) goto leave; @@ -493,33 +453,33 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, mpi_sub_ui (value_e, prime_p, 1); mpi_fdiv_q (value_e, value_e, prime_q ); value_g = mpi_alloc_like (prime_p); - value_h = mpi_alloc_set_ui (1); + value_h = mpi_alloc_set_ui (1); do { mpi_add_ui (value_h, value_h, 1); /* g = h^e mod p */ mpi_powm (value_g, value_h, value_e, prime_p); - } + } while (!mpi_cmp_ui (value_g, 1)); /* Continue until g != 1. */ } /* Select a random number x with: 0 < x < q */ - value_x = gcry_mpi_snew (qbits); - do + value_x = mpi_snew (qbits); + do { if( DBG_CIPHER ) progress('.'); - gcry_mpi_randomize (value_x, qbits, GCRY_VERY_STRONG_RANDOM); + _gcry_mpi_randomize (value_x, qbits, GCRY_VERY_STRONG_RANDOM); mpi_clear_highbit (value_x, qbits+1); - } + } while (!(mpi_cmp_ui (value_x, 0) > 0 && mpi_cmp (value_x, prime_q) < 0)); /* y = g^x mod p */ value_y = mpi_alloc_like (prime_p); - gcry_mpi_powm (value_y, value_g, value_x, prime_p); + mpi_powm (value_y, value_g, value_x, prime_p); - if (DBG_CIPHER) + if (DBG_CIPHER) { progress('\n'); log_mpidump("dsa p", prime_p ); @@ -539,22 +499,22 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, *r_h = value_h; value_h = NULL; leave: - gcry_mpi_release (prime_p); - gcry_mpi_release (prime_q); - gcry_mpi_release (value_g); - gcry_mpi_release (value_y); - gcry_mpi_release (value_x); - gcry_mpi_release (value_h); - gcry_mpi_release (value_e); + _gcry_mpi_release (prime_p); + _gcry_mpi_release (prime_q); + _gcry_mpi_release (value_g); + _gcry_mpi_release (value_y); + _gcry_mpi_release (value_x); + _gcry_mpi_release (value_h); + _gcry_mpi_release (value_e); /* As a last step test this keys (this should never fail of course). */ if (!ec && test_keys (sk, qbits) ) { - gcry_mpi_release (sk->p); sk->p = NULL; - gcry_mpi_release (sk->q); sk->q = NULL; - gcry_mpi_release (sk->g); sk->g = NULL; - gcry_mpi_release (sk->y); sk->y = NULL; - gcry_mpi_release (sk->x); sk->x = NULL; + _gcry_mpi_release (sk->p); sk->p = NULL; + _gcry_mpi_release (sk->q); sk->q = NULL; + _gcry_mpi_release (sk->g); sk->g = NULL; + _gcry_mpi_release (sk->y); sk->y = NULL; + _gcry_mpi_release (sk->x); sk->x = NULL; fips_signal_error ("self-test after key generation failed"); ec = GPG_ERR_SELFTEST_FAILED; } @@ -562,9 +522,9 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, if (ec) { *r_counter = 0; - gcry_free (*r_seed); *r_seed = NULL; + xfree (*r_seed); *r_seed = NULL; *r_seedlen = 0; - gcry_mpi_release (*r_h); *r_h = NULL; + _gcry_mpi_release (*r_h); *r_h = NULL; } return ec; @@ -582,7 +542,7 @@ check_secret_key( DSA_secret_key *sk ) int rc; gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs(sk->y) ); - gcry_mpi_powm( y, sk->g, sk->x, sk->p ); + mpi_powm( y, sk->g, sk->x, sk->p ); rc = !mpi_cmp( y, sk->y ); mpi_free( y ); return rc; @@ -591,20 +551,63 @@ check_secret_key( DSA_secret_key *sk ) /* - Make a DSA signature from HASH and put it into r and s. + Make a DSA signature from INPUT and put it into r and s. + + INPUT may either be a plain MPI or an opaque MPI which is then + internally converted to a plain MPI. FLAGS and HASHALGO may both + be 0 for standard operation mode. + + The return value is 0 on success or an error code. Note that for + backward compatibility the function will not return any error if + FLAGS and HASHALGO are both 0 and INPUT is a plain MPI. */ -static void -sign(gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_secret_key *skey ) +static gpg_err_code_t +sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_secret_key *skey, + int flags, int hashalgo) { + gpg_err_code_t rc; + gcry_mpi_t hash; gcry_mpi_t k; gcry_mpi_t kinv; gcry_mpi_t tmp; + const void *abuf; + unsigned int abits, qbits; + int extraloops = 0; + + qbits = mpi_get_nbits (skey->q); - /* Select a random k with 0 < k < q */ - k = gen_k( skey->q ); + /* Convert the INPUT into an MPI. */ + rc = _gcry_dsa_normalize_hash (input, &hash, qbits); + if (rc) + return rc; + + again: + /* Create the K value. */ + if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo) + { + /* Use Pornin's method for deterministic DSA. If this flag is + set, it is expected that HASH is an opaque MPI with the to be + signed hash. That hash is also used as h1 from 3.2.a. */ + if (!mpi_is_opaque (input)) + { + rc = GPG_ERR_CONFLICT; + goto leave; + } + + abuf = mpi_get_opaque (input, &abits); + rc = _gcry_dsa_gen_rfc6979_k (&k, skey->q, skey->x, + abuf, (abits+7)/8, hashalgo, extraloops); + if (rc) + goto leave; + } + else + { + /* Select a random k with 0 < k < q */ + k = _gcry_dsa_gen_k (skey->q, GCRY_STRONG_RANDOM); + } /* r = (a^k mod p) mod q */ - gcry_mpi_powm( r, skey->g, k, skey->p ); + mpi_powm( r, skey->g, k, skey->p ); mpi_fdiv_r( r, r, skey->q ); /* kinv = k^(-1) mod q */ @@ -620,24 +623,46 @@ sign(gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_secret_key *skey ) mpi_free(k); mpi_free(kinv); mpi_free(tmp); + + if (!mpi_cmp_ui (r, 0)) + { + /* This is a highly unlikely code path. */ + extraloops++; + goto again; + } + + rc = 0; + + leave: + if (hash != input) + mpi_free (hash); + + return rc; } /* Returns true if the signature composed from R and S is valid. */ -static int -verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_public_key *pkey ) +static gpg_err_code_t +verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_public_key *pkey ) { - int rc; + gpg_err_code_t rc = 0; gcry_mpi_t w, u1, u2, v; gcry_mpi_t base[3]; gcry_mpi_t ex[3]; + gcry_mpi_t hash; + unsigned int nbits; if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) ) - return 0; /* assertion 0 < r < q failed */ + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) ) - return 0; /* assertion 0 < s < q failed */ + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ + + nbits = mpi_get_nbits (pkey->q); + rc = _gcry_dsa_normalize_hash (input, &hash, nbits); + if (rc) + return rc; w = mpi_alloc( mpi_get_nlimbs(pkey->q) ); u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) ); @@ -660,12 +685,25 @@ verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_public_key *pkey ) mpi_mulpowm( v, base, ex, pkey->p ); mpi_fdiv_r( v, v, pkey->q ); - rc = !mpi_cmp( v, r ); + if (mpi_cmp( v, r )) + { + if (DBG_CIPHER) + { + log_mpidump (" i", input); + log_mpidump (" h", hash); + log_mpidump (" v", v); + log_mpidump (" r", r); + log_mpidump (" s", s); + } + rc = GPG_ERR_BAD_SIGNATURE; + } mpi_free(w); mpi_free(u1); mpi_free(u2); mpi_free(v); + if (hash != input) + mpi_free (hash); return rc; } @@ -676,366 +714,458 @@ verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_public_key *pkey ) *********************************************/ static gcry_err_code_t -dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue, - const gcry_sexp_t genparms, - gcry_mpi_t *skey, gcry_mpi_t **retfactors, - gcry_sexp_t *r_extrainfo) +dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) { - gpg_err_code_t ec; + gpg_err_code_t rc; + unsigned int nbits; + gcry_sexp_t domainsexp; DSA_secret_key sk; gcry_sexp_t l1; unsigned int qbits = 0; gcry_sexp_t deriveparms = NULL; gcry_sexp_t seedinfo = NULL; - int transient_key = 0; - int use_fips186_2 = 0; - int use_fips186 = 0; + gcry_sexp_t misc_info = NULL; + int flags = 0; dsa_domain_t domain; - - (void)algo; /* No need to check it. */ - (void)evalue; /* Not required for DSA. */ + gcry_mpi_t *factors = NULL; + memset (&sk, 0, sizeof sk); memset (&domain, 0, sizeof domain); - if (genparms) + rc = _gcry_pk_util_get_nbits (genparms, &nbits); + if (rc) + return rc; + + /* Parse the optional flags list. */ + l1 = sexp_find_token (genparms, "flags", 0); + if (l1) { - gcry_sexp_t domainsexp; - - /* Parse the optional qbits element. */ - l1 = gcry_sexp_find_token (genparms, "qbits", 0); - if (l1) + rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); + sexp_release (l1); + if (rc) + return rc;\ + } + + /* Parse the optional qbits element. */ + l1 = sexp_find_token (genparms, "qbits", 0); + if (l1) + { + char buf[50]; + const char *s; + size_t n; + + s = sexp_nth_data (l1, 1, &n); + if (!s || n >= DIM (buf) - 1 ) { - char buf[50]; - const char *s; - size_t n; - - s = gcry_sexp_nth_data (l1, 1, &n); - if (!s || n >= DIM (buf) - 1 ) - { - gcry_sexp_release (l1); - return GPG_ERR_INV_OBJ; /* No value or value too large. */ - } - memcpy (buf, s, n); - buf[n] = 0; - qbits = (unsigned int)strtoul (buf, NULL, 0); - gcry_sexp_release (l1); + sexp_release (l1); + return GPG_ERR_INV_OBJ; /* No value or value too large. */ } + memcpy (buf, s, n); + buf[n] = 0; + qbits = (unsigned int)strtoul (buf, NULL, 0); + sexp_release (l1); + } - /* Parse the optional transient-key flag. */ - l1 = gcry_sexp_find_token (genparms, "transient-key", 0); + /* Parse the optional transient-key flag. */ + if (!(flags & PUBKEY_FLAG_TRANSIENT_KEY)) + { + l1 = sexp_find_token (genparms, "transient-key", 0); if (l1) { - transient_key = 1; - gcry_sexp_release (l1); + flags |= PUBKEY_FLAG_TRANSIENT_KEY; + sexp_release (l1); } + } - /* Get the optional derive parameters. */ - deriveparms = gcry_sexp_find_token (genparms, "derive-parms", 0); + /* Get the optional derive parameters. */ + deriveparms = sexp_find_token (genparms, "derive-parms", 0); - /* Parse the optional "use-fips186" flags. */ - l1 = gcry_sexp_find_token (genparms, "use-fips186", 0); + /* Parse the optional "use-fips186" flags. */ + if (!(flags & PUBKEY_FLAG_USE_FIPS186)) + { + l1 = sexp_find_token (genparms, "use-fips186", 0); if (l1) { - use_fips186 = 1; - gcry_sexp_release (l1); + flags |= PUBKEY_FLAG_USE_FIPS186; + sexp_release (l1); } - l1 = gcry_sexp_find_token (genparms, "use-fips186-2", 0); + } + if (!(flags & PUBKEY_FLAG_USE_FIPS186_2)) + { + l1 = sexp_find_token (genparms, "use-fips186-2", 0); if (l1) { - use_fips186_2 = 1; - gcry_sexp_release (l1); + flags |= PUBKEY_FLAG_USE_FIPS186_2; + sexp_release (l1); } + } - /* Check whether domain parameters are given. */ - domainsexp = gcry_sexp_find_token (genparms, "domain", 0); - if (domainsexp) + /* Check whether domain parameters are given. */ + domainsexp = sexp_find_token (genparms, "domain", 0); + if (domainsexp) + { + /* DERIVEPARMS can't be used together with domain parameters. + NBITS abnd QBITS may not be specified because there values + are derived from the domain parameters. */ + if (deriveparms || qbits || nbits) { - /* DERIVEPARMS can't be used together with domain - parameters. NBITS abnd QBITS may not be specified - because there values are derived from the domain - parameters. */ - if (deriveparms || qbits || nbits) - { - gcry_sexp_release (domainsexp); - gcry_sexp_release (deriveparms); - return GPG_ERR_INV_VALUE; - } - - /* Put all domain parameters into the domain object. */ - l1 = gcry_sexp_find_token (domainsexp, "p", 0); - domain.p = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (l1); - l1 = gcry_sexp_find_token (domainsexp, "q", 0); - domain.q = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (l1); - l1 = gcry_sexp_find_token (domainsexp, "g", 0); - domain.g = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (l1); - gcry_sexp_release (domainsexp); - - /* Check that all domain parameters are available. */ - if (!domain.p || !domain.q || !domain.g) - { - gcry_mpi_release (domain.p); - gcry_mpi_release (domain.q); - gcry_mpi_release (domain.g); - gcry_sexp_release (deriveparms); - return GPG_ERR_MISSING_VALUE; - } + sexp_release (domainsexp); + sexp_release (deriveparms); + return GPG_ERR_INV_VALUE; + } - /* Get NBITS and QBITS from the domain parameters. */ - nbits = mpi_get_nbits (domain.p); - qbits = mpi_get_nbits (domain.q); + /* Put all domain parameters into the domain object. */ + l1 = sexp_find_token (domainsexp, "p", 0); + domain.p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + l1 = sexp_find_token (domainsexp, "q", 0); + domain.q = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + l1 = sexp_find_token (domainsexp, "g", 0); + domain.g = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + sexp_release (domainsexp); + + /* Check that all domain parameters are available. */ + if (!domain.p || !domain.q || !domain.g) + { + _gcry_mpi_release (domain.p); + _gcry_mpi_release (domain.q); + _gcry_mpi_release (domain.g); + sexp_release (deriveparms); + return GPG_ERR_MISSING_VALUE; } + + /* Get NBITS and QBITS from the domain parameters. */ + nbits = mpi_get_nbits (domain.p); + qbits = mpi_get_nbits (domain.q); } - if (deriveparms || use_fips186 || use_fips186_2 || fips_mode ()) + if (deriveparms + || (flags & PUBKEY_FLAG_USE_FIPS186) + || (flags & PUBKEY_FLAG_USE_FIPS186_2) + || fips_mode ()) { int counter; void *seed; size_t seedlen; gcry_mpi_t h_value; - ec = generate_fips186 (&sk, nbits, qbits, deriveparms, use_fips186_2, + rc = generate_fips186 (&sk, nbits, qbits, deriveparms, + !!(flags & PUBKEY_FLAG_USE_FIPS186_2), &domain, &counter, &seed, &seedlen, &h_value); - gcry_sexp_release (deriveparms); - if (!ec && h_value) + if (!rc && h_value) { /* Format the seed-values unless domain parameters are used for which a H_VALUE of NULL is an indication. */ - ec = gpg_err_code (gcry_sexp_build - (&seedinfo, NULL, - "(seed-values(counter %d)(seed %b)(h %m))", - counter, (int)seedlen, seed, h_value)); - if (ec) - { - gcry_mpi_release (sk.p); sk.p = NULL; - gcry_mpi_release (sk.q); sk.q = NULL; - gcry_mpi_release (sk.g); sk.g = NULL; - gcry_mpi_release (sk.y); sk.y = NULL; - gcry_mpi_release (sk.x); sk.x = NULL; - } - gcry_free (seed); - gcry_mpi_release (h_value); + rc = sexp_build (&seedinfo, NULL, + "(seed-values(counter %d)(seed %b)(h %m))", + counter, (int)seedlen, seed, h_value); + xfree (seed); + _gcry_mpi_release (h_value); } } else { - ec = generate (&sk, nbits, qbits, transient_key, &domain, retfactors); + rc = generate (&sk, nbits, qbits, + !!(flags & PUBKEY_FLAG_TRANSIENT_KEY), + &domain, &factors); } - gcry_mpi_release (domain.p); - gcry_mpi_release (domain.q); - gcry_mpi_release (domain.g); - - if (!ec) + if (!rc) { - skey[0] = sk.p; - skey[1] = sk.q; - skey[2] = sk.g; - skey[3] = sk.y; - skey[4] = sk.x; - - if (!r_extrainfo) - { - /* Old style interface - return the factors - if any - at - retfactors. */ - } - else if (!*retfactors && !seedinfo) - { - /* No factors and no seedinfo, thus there is nothing to return. */ - *r_extrainfo = NULL; - } + /* Put the factors into MISC_INFO. Note that the factors are + not confidential thus we can store them in standard memory. */ + int nfactors, i, j; + char *p; + char *format = NULL; + void **arg_list = NULL; + + for (nfactors=0; factors && factors[nfactors]; nfactors++) + ; + /* Allocate space for the format string: + "(misc-key-info%S(pm1-factors%m))" + with one "%m" for each factor and construct it. */ + format = xtrymalloc (50 + 2*nfactors); + if (!format) + rc = gpg_err_code_from_syserror (); else { - /* Put the factors into extrainfo and set retfactors to NULL - to make use of the new interface. Note that the factors - are not confidential thus we can store them in standard - memory. */ - int nfactors, i, j; - char *p; - char *format = NULL; - void **arg_list = NULL; - - for (nfactors=0; *retfactors && (*retfactors)[nfactors]; nfactors++) - ; - /* Allocate space for the format string: - "(misc-key-info%S(pm1-factors%m))" - with one "%m" for each factor and construct it. */ - format = gcry_malloc (50 + 2*nfactors); - if (!format) - ec = gpg_err_code_from_syserror (); - else + p = stpcpy (format, "(misc-key-info"); + if (seedinfo) + p = stpcpy (p, "%S"); + if (nfactors) { - p = stpcpy (format, "(misc-key-info"); - if (seedinfo) - p = stpcpy (p, "%S"); - if (nfactors) - { - p = stpcpy (p, "(pm1-factors"); - for (i=0; i < nfactors; i++) - p = stpcpy (p, "%m"); - p = stpcpy (p, ")"); - } + p = stpcpy (p, "(pm1-factors"); + for (i=0; i < nfactors; i++) + p = stpcpy (p, "%m"); p = stpcpy (p, ")"); - - /* Allocate space for the list of factors plus one for - an S-expression plus an extra NULL entry for safety - and fill it with the factors. */ - arg_list = gcry_calloc (nfactors+1+1, sizeof *arg_list); - if (!arg_list) - ec = gpg_err_code_from_syserror (); - else - { - i = 0; - if (seedinfo) - arg_list[i++] = &seedinfo; - for (j=0; j < nfactors; j++) - arg_list[i++] = (*retfactors) + j; - arg_list[i] = NULL; - - ec = gpg_err_code (gcry_sexp_build_array - (r_extrainfo, NULL, format, arg_list)); - } - } - - gcry_free (arg_list); - gcry_free (format); - for (i=0; i < nfactors; i++) - { - gcry_mpi_release ((*retfactors)[i]); - (*retfactors)[i] = NULL; } - gcry_free (*retfactors); - *retfactors = NULL; - if (ec) + p = stpcpy (p, ")"); + + /* Allocate space for the list of factors plus one for the + seedinfo s-exp plus an extra NULL entry for safety and + fill it with the factors. */ + arg_list = xtrycalloc (nfactors+1+1, sizeof *arg_list); + if (!arg_list) + rc = gpg_err_code_from_syserror (); + else { - for (i=0; i < 5; i++) - { - gcry_mpi_release (skey[i]); - skey[i] = NULL; - } + i = 0; + if (seedinfo) + arg_list[i++] = &seedinfo; + for (j=0; j < nfactors; j++) + arg_list[i++] = factors + j; + arg_list[i] = NULL; + + rc = sexp_build_array (&misc_info, NULL, format, arg_list); } } - } - - gcry_sexp_release (seedinfo); - return ec; -} + xfree (arg_list); + xfree (format); + } -static gcry_err_code_t -dsa_generate (int algo, unsigned int nbits, unsigned long evalue, - gcry_mpi_t *skey, gcry_mpi_t **retfactors) -{ - (void)evalue; - return dsa_generate_ext (algo, nbits, 0, NULL, skey, retfactors, NULL); + if (!rc) + rc = sexp_build (r_skey, NULL, + "(key-data" + " (public-key" + " (dsa(p%m)(q%m)(g%m)(y%m)))" + " (private-key" + " (dsa(p%m)(q%m)(g%m)(y%m)(x%m)))" + " %S)", + sk.p, sk.q, sk.g, sk.y, + sk.p, sk.q, sk.g, sk.y, sk.x, + misc_info); + + + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.q); + _gcry_mpi_release (sk.g); + _gcry_mpi_release (sk.y); + _gcry_mpi_release (sk.x); + + _gcry_mpi_release (domain.p); + _gcry_mpi_release (domain.q); + _gcry_mpi_release (domain.g); + + sexp_release (seedinfo); + sexp_release (misc_info); + sexp_release (deriveparms); + if (factors) + { + gcry_mpi_t *mp; + for (mp = factors; *mp; mp++) + mpi_free (*mp); + xfree (factors); + } + return rc; } static gcry_err_code_t -dsa_check_secret_key (int algo, gcry_mpi_t *skey) +dsa_check_secret_key (gcry_sexp_t keyparms) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - DSA_secret_key sk; + gcry_err_code_t rc; + DSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL}; - (void)algo; + rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx", + &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, + NULL); + if (rc) + goto leave; - if ((! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3]) || (! skey[4])) - err = GPG_ERR_BAD_MPI; - else - { - sk.p = skey[0]; - sk.q = skey[1]; - sk.g = skey[2]; - sk.y = skey[3]; - sk.x = skey[4]; - if (! check_secret_key (&sk)) - err = GPG_ERR_BAD_SECKEY; - } + if (!check_secret_key (&sk)) + rc = GPG_ERR_BAD_SECKEY; - return err; + leave: + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.q); + _gcry_mpi_release (sk.g); + _gcry_mpi_release (sk.y); + _gcry_mpi_release (sk.x); + if (DBG_CIPHER) + log_debug ("dsa_testkey => %s\n", gpg_strerror (rc)); + return rc; } static gcry_err_code_t -dsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey) +dsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - DSA_secret_key sk; + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_mpi_t data = NULL; + DSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL}; + gcry_mpi_t sig_r = NULL; + gcry_mpi_t sig_s = NULL; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, + dsa_get_nbits (keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("dsa_sign data", data); - (void)algo; + /* Extract the key. */ + rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx", + &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("dsa_sign p", sk.p); + log_mpidump ("dsa_sign q", sk.q); + log_mpidump ("dsa_sign g", sk.g); + log_mpidump ("dsa_sign y", sk.y); + if (!fips_mode ()) + log_mpidump ("dsa_sign x", sk.x); + } - if ((! data) - || (! skey[0]) || (! skey[1]) || (! skey[2]) - || (! skey[3]) || (! skey[4])) - err = GPG_ERR_BAD_MPI; - else + sig_r = mpi_new (0); + sig_s = mpi_new (0); + rc = sign (sig_r, sig_s, data, &sk, ctx.flags, ctx.hash_algo); + if (rc) + goto leave; + if (DBG_CIPHER) { - sk.p = skey[0]; - sk.q = skey[1]; - sk.g = skey[2]; - sk.y = skey[3]; - sk.x = skey[4]; - resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.p)); - resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.p)); - sign (resarr[0], resarr[1], data, &sk); + log_mpidump ("dsa_sign sig_r", sig_r); + log_mpidump ("dsa_sign sig_s", sig_s); } - return err; + rc = sexp_build (r_sig, NULL, "(sig-val(dsa(r%M)(s%M)))", sig_r, sig_s); + + leave: + _gcry_mpi_release (sig_r); + _gcry_mpi_release (sig_s); + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.q); + _gcry_mpi_release (sk.g); + _gcry_mpi_release (sk.y); + _gcry_mpi_release (sk.x); + _gcry_mpi_release (data); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("dsa_sign => %s\n", gpg_strerror (rc)); + return rc; } + static gcry_err_code_t -dsa_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, - int (*cmp) (void *, gcry_mpi_t), void *opaquev) +dsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - DSA_public_key pk; - - (void)algo; - (void)cmp; - (void)opaquev; + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + gcry_mpi_t sig_r = NULL; + gcry_mpi_t sig_s = NULL; + gcry_mpi_t data = NULL; + DSA_public_key pk = { NULL, NULL, NULL, NULL }; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, + dsa_get_nbits (s_keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("dsa_verify data", data); + + /* Extract the signature value. */ + rc = _gcry_pk_util_preparse_sigval (s_sig, dsa_names, &l1, NULL); + if (rc) + goto leave; + rc = _gcry_sexp_extract_param (l1, NULL, "rs", &sig_r, &sig_s, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("dsa_verify s_r", sig_r); + log_mpidump ("dsa_verify s_s", sig_s); + } - if ((! data[0]) || (! data[1]) || (! hash) - || (! pkey[0]) || (! pkey[1]) || (! pkey[2]) || (! pkey[3])) - err = GPG_ERR_BAD_MPI; - else + /* Extract the key. */ + rc = _gcry_sexp_extract_param (s_keyparms, NULL, "pqgy", + &pk.p, &pk.q, &pk.g, &pk.y, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) { - pk.p = pkey[0]; - pk.q = pkey[1]; - pk.g = pkey[2]; - pk.y = pkey[3]; - if (! verify (data[0], data[1], hash, &pk)) - err = GPG_ERR_BAD_SIGNATURE; + log_mpidump ("dsa_verify p", pk.p); + log_mpidump ("dsa_verify q", pk.q); + log_mpidump ("dsa_verify g", pk.g); + log_mpidump ("dsa_verify y", pk.y); } - return err; + + /* Verify the signature. */ + rc = verify (sig_r, sig_s, data, &pk); + + leave: + _gcry_mpi_release (pk.p); + _gcry_mpi_release (pk.q); + _gcry_mpi_release (pk.g); + _gcry_mpi_release (pk.y); + _gcry_mpi_release (data); + _gcry_mpi_release (sig_r); + _gcry_mpi_release (sig_s); + sexp_release (l1); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("dsa_verify => %s\n", rc?gpg_strerror (rc):"Good"); + return rc; } +/* Return the number of bits for the key described by PARMS. On error + * 0 is returned. The format of PARMS starts with the algorithm name; + * for example: + * + * (dsa + * (p <mpi>) + * (q <mpi>) + * (g <mpi>) + * (y <mpi>)) + * + * More parameters may be given but we only need P here. + */ static unsigned int -dsa_get_nbits (int algo, gcry_mpi_t *pkey) +dsa_get_nbits (gcry_sexp_t parms) { - (void)algo; - - return mpi_get_nbits (pkey[0]); + gcry_sexp_t l1; + gcry_mpi_t p; + unsigned int nbits; + + l1 = sexp_find_token (parms, "p", 1); + if (!l1) + return 0; /* Parameter P not found. */ + + p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + nbits = p? mpi_get_nbits (p) : 0; + _gcry_mpi_release (p); + return nbits; } -/* +/* Self-test section. */ static const char * selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) { - static const char sample_data[] = - "(data (flags pkcs1)" - " (hash sha1 #a0b1c2d3e4f500102030405060708090a1b2c3d4#))"; - static const char sample_data_bad[] = - "(data (flags pkcs1)" - " (hash sha1 #a0b1c2d3e4f510102030405060708090a1b2c3d4#))"; + static const char sample_data[] = + "(data (flags raw)" + " (value #a0b1c2d3e4f500102030405060708090a1b2c3d4#))"; + static const char sample_data_bad[] = + "(data (flags raw)" + " (value #a0b1c2d3e4f510102030405060708090a1b2c3d4#))"; const char *errtxt = NULL; gcry_error_t err; @@ -1043,30 +1173,29 @@ selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) gcry_sexp_t data_bad = NULL; gcry_sexp_t sig = NULL; - err = gcry_sexp_sscan (&data, NULL, - sample_data, strlen (sample_data)); + err = sexp_sscan (&data, NULL, sample_data, strlen (sample_data)); if (!err) - err = gcry_sexp_sscan (&data_bad, NULL, - sample_data_bad, strlen (sample_data_bad)); + err = sexp_sscan (&data_bad, NULL, + sample_data_bad, strlen (sample_data_bad)); if (err) { errtxt = "converting data failed"; goto leave; } - err = gcry_pk_sign (&sig, data, skey); + err = _gcry_pk_sign (&sig, data, skey); if (err) { errtxt = "signing failed"; goto leave; } - err = gcry_pk_verify (sig, data, pkey); + err = _gcry_pk_verify (sig, data, pkey); if (err) { errtxt = "verify failed"; goto leave; } - err = gcry_pk_verify (sig, data_bad, pkey); + err = _gcry_pk_verify (sig, data_bad, pkey); if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE) { errtxt = "bad signature not detected"; @@ -1075,9 +1204,9 @@ selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) leave: - gcry_sexp_release (sig); - gcry_sexp_release (data_bad); - gcry_sexp_release (data); + sexp_release (sig); + sexp_release (data_bad); + sexp_release (data); return errtxt; } @@ -1093,22 +1222,21 @@ selftests_dsa (selftest_report_func_t report) /* Convert the S-expressions into the internal representation. */ what = "convert"; - err = gcry_sexp_sscan (&skey, NULL, - sample_secret_key, strlen (sample_secret_key)); + err = sexp_sscan (&skey, NULL, sample_secret_key, strlen (sample_secret_key)); if (!err) - err = gcry_sexp_sscan (&pkey, NULL, - sample_public_key, strlen (sample_public_key)); + err = sexp_sscan (&pkey, NULL, + sample_public_key, strlen (sample_public_key)); if (err) { - errtxt = gcry_strerror (err); + errtxt = _gcry_strerror (err); goto failed; } what = "key consistency"; - err = gcry_pk_testkey (skey); + err = _gcry_pk_testkey (skey); if (err) { - errtxt = gcry_strerror (err); + errtxt = _gcry_strerror (err); goto failed; } @@ -1117,13 +1245,13 @@ selftests_dsa (selftest_report_func_t report) if (errtxt) goto failed; - gcry_sexp_release (pkey); - gcry_sexp_release (skey); + sexp_release (pkey); + sexp_release (skey); return 0; /* Succeeded. */ failed: - gcry_sexp_release (pkey); - gcry_sexp_release (skey); + sexp_release (pkey); + sexp_release (skey); if (report) report ("pubkey", GCRY_PK_DSA, what, errtxt); return GPG_ERR_SELFTEST_FAILED; @@ -1146,7 +1274,7 @@ run_selftests (int algo, int extended, selftest_report_func_t report) default: ec = GPG_ERR_PUBKEY_ALGO; break; - + } return ec; } @@ -1154,29 +1282,18 @@ run_selftests (int algo, int extended, selftest_report_func_t report) -static const char *dsa_names[] = - { - "dsa", - "openpgp-dsa", - NULL, - }; - gcry_pk_spec_t _gcry_pubkey_spec_dsa = { - "DSA", dsa_names, - "pqgy", "pqgyx", "", "rs", "pqgy", + GCRY_PK_DSA, { 0, 1 }, GCRY_PK_USAGE_SIGN, + "DSA", dsa_names, + "pqgy", "pqgyx", "", "rs", "pqgy", dsa_generate, dsa_check_secret_key, NULL, NULL, dsa_sign, dsa_verify, - dsa_get_nbits + dsa_get_nbits, + run_selftests }; -pk_extra_spec_t _gcry_pubkey_extraspec_dsa = - { - run_selftests, - dsa_generate_ext - }; - |