summaryrefslogtreecommitdiff
path: root/cipher
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2013-07-19 18:14:38 +0200
committerWerner Koch <wk@gnupg.org>2013-07-19 18:14:38 +0200
commit37d0a1ebdc2dc74df4fb6bf0621045018122a68f (patch)
treeb516be67206ef44bcb92076faa7afcceb12d98b7 /cipher
parent2d3e8d4d9562d666420aadd9ffa8ac0456a1cd91 (diff)
downloadlibgcrypt-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.c42
-rw-r--r--cipher/ecc.c36
-rw-r--r--cipher/elgamal.c6
-rw-r--r--cipher/pubkey.c61
-rw-r--r--cipher/rsa.c8
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 );