diff options
author | Werner Koch <wk@gnupg.org> | 2013-07-19 18:14:38 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2013-07-19 18:14:38 +0200 |
commit | 37d0a1ebdc2dc74df4fb6bf0621045018122a68f (patch) | |
tree | b516be67206ef44bcb92076faa7afcceb12d98b7 /cipher | |
parent | 2d3e8d4d9562d666420aadd9ffa8ac0456a1cd91 (diff) | |
download | libgcrypt-37d0a1ebdc2dc74df4fb6bf0621045018122a68f.tar.gz |
pk: Allow the use of a hash element for DSA sign and verify.
* cipher/pubkey.c (pubkey_sign): Add arg ctx and pass it to the sign
module.
(gcry_pk_sign): Pass CTX to pubkey_sign.
(sexp_data_to_mpi): Add flag rfc6979 and code to alls hash with *DSA
* cipher/rsa.c (rsa_sign, rsa_verify): Return an error if an opaque
MPI is given for DATA/HASH.
* cipher/elgamal.c (elg_sign, elg_verify): Ditto.
* cipher/dsa.c (dsa_sign, dsa_verify): Convert a given opaque MPI.
* cipher/ecc.c (ecc_sign, ecc_verify): Ditto.
* tests/basic.c (check_pubkey_sign_ecdsa): Add a test for using a hash
element with DSA.
--
This patch allows the use of
(data (flags raw)
(hash sha256 #80112233445566778899AABBCCDDEEFF
000102030405060708090A0B0C0D0E0F#))
in addition to the old but more efficient
(data (flags raw)
(value #80112233445566778899AABBCCDDEEFF
000102030405060708090A0B0C0D0E0F#))
for DSA and ECDSA. With the hash element the flag "raw" must be
explicitly given because existing regression test code expects that
conflict error is return if no flags but a hash element is given.
Note that the hash algorithm name is currently not checked. It may
eventually be used to cross-check the length of the provided hash
value. It is suggested that the correct hash name is given - even if
a truncated hash value is used.
Finally this patch adds a way to pass the hash algorithm and flag
values to the signing module. "rfc6979" as been implemented as a new
but not yet used flag.
Signed-off-by: Werner Koch <wk@gnupg.org>
Diffstat (limited to 'cipher')
-rw-r--r-- | cipher/dsa.c | 42 | ||||
-rw-r--r-- | cipher/ecc.c | 36 | ||||
-rw-r--r-- | cipher/elgamal.c | 6 | ||||
-rw-r--r-- | cipher/pubkey.c | 61 | ||||
-rw-r--r-- | cipher/rsa.c | 8 |
5 files changed, 139 insertions, 14 deletions
diff --git a/cipher/dsa.c b/cipher/dsa.c index 55805e21..7652c19f 100644 --- a/cipher/dsa.c +++ b/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. * @@ -539,7 +540,7 @@ check_secret_key( DSA_secret_key *sk ) Make a DSA signature from HASH and put it into r and s. */ static void -sign(gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_secret_key *skey ) +sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_secret_key *skey ) { gcry_mpi_t k; gcry_mpi_t kinv; @@ -929,7 +930,22 @@ dsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey, 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); + if (mpi_is_opaque (data)) + { + const void *abuf; + unsigned int abits; + gcry_mpi_t a; + + abuf = gcry_mpi_get_opaque (data, &abits); + err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, abits/8, NULL); + if (!err) + { + sign (resarr[0], resarr[1], a, &sk); + gcry_mpi_release (a); + } + } + else + sign (resarr[0], resarr[1], data, &sk); } return err; } @@ -954,8 +970,26 @@ dsa_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, 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; + if (mpi_is_opaque (hash)) + { + const void *abuf; + unsigned int abits; + gcry_mpi_t a; + + abuf = gcry_mpi_get_opaque (hash, &abits); + err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, abits/8, NULL); + if (!err) + { + if (!verify (data[0], data[1], a, &pk)) + err = GPG_ERR_BAD_SIGNATURE; + gcry_mpi_release (a); + } + } + else + { + if (!verify (data[0], data[1], hash, &pk)) + err = GPG_ERR_BAD_SIGNATURE; + } } return err; } diff --git a/cipher/ecc.c b/cipher/ecc.c index e4b1799e..725dfbe6 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -1347,7 +1347,24 @@ ecc_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey, resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.E.p)); resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.E.p)); - err = sign (data, &sk, resarr[0], resarr[1]); + + if (mpi_is_opaque (data)) + { + const void *abuf; + unsigned int abits; + gcry_mpi_t a; + + abuf = gcry_mpi_get_opaque (data, &abits); + err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, abits/8, NULL); + if (!err) + { + err = sign (a, &sk, resarr[0], resarr[1]); + gcry_mpi_release (a); + } + } + else + err = sign (data, &sk, resarr[0], resarr[1]); + if (err) { mpi_free (resarr[0]); @@ -1394,7 +1411,22 @@ ecc_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, return err; } - err = verify (hash, &pk, data[0], data[1]); + if (mpi_is_opaque (hash)) + { + const void *abuf; + unsigned int abits; + gcry_mpi_t a; + + abuf = gcry_mpi_get_opaque (hash, &abits); + err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, abits/8, NULL); + if (!err) + { + err = verify (a, &pk, data[0], data[1]); + gcry_mpi_release (a); + } + } + else + err = verify (hash, &pk, data[0], data[1]); point_free (&pk.E.G); point_free (&pk.Q); diff --git a/cipher/elgamal.c b/cipher/elgamal.c index 128dd997..b40d1324 100644 --- a/cipher/elgamal.c +++ b/cipher/elgamal.c @@ -763,6 +763,9 @@ elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey, (void)flags; (void)hashalgo; + if (mpi_is_opaque (data)) + return GPG_ERR_INV_DATA; + if ((! data) || (! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3])) err = GPG_ERR_BAD_MPI; @@ -792,6 +795,9 @@ elg_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, (void)cmp; (void)opaquev; + if (mpi_is_opaque (hash)) + return GPG_ERR_INV_DATA; + if ((! data[0]) || (! data[1]) || (! hash) || (! pkey[0]) || (! pkey[1]) || (! pkey[2])) err = GPG_ERR_BAD_MPI; diff --git a/cipher/pubkey.c b/cipher/pubkey.c index 23a43589..606cedf8 100644 --- a/cipher/pubkey.c +++ b/cipher/pubkey.c @@ -37,7 +37,8 @@ static gcry_err_code_t pubkey_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data, gcry_mpi_t *skey, int flags); static gcry_err_code_t pubkey_sign (int algo, gcry_mpi_t *resarr, - gcry_mpi_t hash, gcry_mpi_t *skey); + gcry_mpi_t hash, gcry_mpi_t *skey, + struct pk_encoding_ctx *ctx); static gcry_err_code_t pubkey_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, int (*cmp) (void *, gcry_mpi_t), @@ -712,7 +713,7 @@ pubkey_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data, */ static gcry_err_code_t pubkey_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *skey) + gcry_mpi_t *skey, struct pk_encoding_ctx *ctx) { gcry_pk_spec_t *pubkey; gcry_module_t module; @@ -732,7 +733,8 @@ pubkey_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, if (module) { pubkey = (gcry_pk_spec_t *) module->spec; - rc = pubkey->sign (algorithm, resarr, data, skey, 0, 0); + rc = pubkey->sign (algorithm, resarr, data, skey, + ctx->flags, ctx->hash_algo); _gcry_module_release (module); goto ready; } @@ -2477,7 +2479,7 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo, (<mpi>) or (data - [(flags [raw, pkcs1, oaep, pss, no-blinding])] + [(flags [raw, direct, pkcs1, oaep, pss, no-blinding, rfc6979])] [(hash <algo> <value>)] [(value <text>)] [(hash-algo <algo>)] @@ -2504,8 +2506,9 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, int i; size_t n; const char *s; - int unknown_flag=0; + int unknown_flag = 0; int parsed_flags = 0; + int explicit_raw = 0; *ret_mpi = NULL; ldata = gcry_sexp_find_token (input, "data", 0); @@ -2525,9 +2528,14 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, s = gcry_sexp_nth_data (lflags, i, &n); if (!s) ; /* not a data element*/ + else if (n == 7 && ! memcmp (s, "rfc6979", 7)) + parsed_flags |= PUBKEY_FLAG_RFC6979; else if ( n == 3 && !memcmp (s, "raw", 3) && ctx->encoding == PUBKEY_ENC_UNKNOWN) - ctx->encoding = PUBKEY_ENC_RAW; + { + ctx->encoding = PUBKEY_ENC_RAW; + explicit_raw = 1; + } else if ( n == 5 && !memcmp (s, "pkcs1", 5) && ctx->encoding == PUBKEY_ENC_UNKNOWN) ctx->encoding = PUBKEY_ENC_PKCS1; @@ -2557,8 +2565,47 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, rc = GPG_ERR_INV_OBJ; /* none or both given */ else if (unknown_flag) rc = GPG_ERR_INV_FLAG; + else if (ctx->encoding == PUBKEY_ENC_RAW && lhash + && (explicit_raw || (parsed_flags & PUBKEY_FLAG_RFC6979))) + { + /* Raw encoding along with a hash element. This is commonly + used for DSA. For better backward error compatibility we + allow this only if either the rfc6979 flag has been given or + the raw flags was explicitly given. */ + if (gcry_sexp_length (lhash) != 3) + rc = GPG_ERR_INV_OBJ; + else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n ) + rc = GPG_ERR_INV_OBJ; + else + { + void *value; + size_t valuelen; + + ctx->hash_algo = get_hash_algo (s, n); + if (!ctx->hash_algo) + rc = GPG_ERR_DIGEST_ALGO; + else if (!(value=gcry_sexp_nth_buffer (lhash, 2, &valuelen))) + rc = GPG_ERR_INV_OBJ; + else if ((valuelen * 8) < valuelen) + { + gcry_free (value); + rc = GPG_ERR_TOO_LARGE; + } + else + *ret_mpi = gcry_mpi_set_opaque (NULL, value, valuelen*8); + } + } else if (ctx->encoding == PUBKEY_ENC_RAW && lvalue) { + /* RFC6969 may only be used with the a hash value and not the + MPI based value. */ + if (parsed_flags & PUBKEY_FLAG_RFC6979) + { + rc = GPG_ERR_CONFLICT; + goto leave; + } + + /* Get the value */ *ret_mpi = gcry_sexp_nth_mpi (lvalue, 1, GCRYMPI_FMT_USG); if (!*ret_mpi) rc = GPG_ERR_INV_OBJ; @@ -3214,7 +3261,7 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey) rc = gpg_err_code_from_syserror (); goto leave; } - rc = pubkey_sign (module->mod_id, result, hash, skey); + rc = pubkey_sign (module->mod_id, result, hash, skey, &ctx); if (rc) goto leave; diff --git a/cipher/rsa.c b/cipher/rsa.c index 4787f813..c9fcebf0 100644 --- a/cipher/rsa.c +++ b/cipher/rsa.c @@ -700,7 +700,7 @@ stronger_key_check ( RSA_secret_key *skey ) * Where m is OUTPUT, c is INPUT and d,n,p,q,u are elements of SKEY. */ static void -secret(gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey ) +secret (gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey ) { if (!skey->p || !skey->q || !skey->u) { @@ -1002,6 +1002,9 @@ rsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey, (void)flags; (void)hashalgo; + if (mpi_is_opaque (data)) + return GPG_ERR_INV_DATA; + sk.n = skey[0]; sk.e = skey[1]; sk.d = skey[2]; @@ -1028,6 +1031,9 @@ rsa_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, (void)cmp; (void)opaquev; + if (mpi_is_opaque (hash)) + return GPG_ERR_INV_DATA; + pk.n = pkey[0]; pk.e = pkey[1]; result = gcry_mpi_new ( 160 ); |