summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2013-10-09 15:05:26 +0200
committerWerner Koch <wk@gnupg.org>2013-10-09 15:05:26 +0200
commit94b652ecb006c29fa2ffb1badc9f02b758581737 (patch)
tree14eb5e6121fafcf13d46eddb2e53d3b176ac6c8e
parent4645f3728bb0900591b0aef85831fdee52c59e3c (diff)
downloadlibgcrypt-94b652ecb006c29fa2ffb1badc9f02b758581737.tar.gz
pubkey: Move sexp parsing for gcry_pk_verify to the modules.
* cipher/rsa.c (rsa_verify): Revamp. * cipher/dsa.c (dsa_verify): Revamp. * cipher/elgamal.c (elg_verify): Revamp. * cipher/ecc.c (ecc_verify): Revamp. * cipher/pubkey.c (sexp_to_sig): Remove. (pss_verify_cmp): Move to pubkey-util.c (sexp_data_to_mpi): Ditto. (init_encoding_ctx): Ditto. (gcry_pk_verify): Simplify. * cipher/pubkey-util.c (_gcry_pk_util_init_encoding_ctx): Add. Take from pubkey.c (get_hash_algo): Ditto. (_gcry_pk_util_data_to_mpi): Ditto. (pss_verify_cmp): Ditto. (_gcry_pk_util_extract_mpis): New. (_gcry_pk_util_preparse_sigval): New. (_gcry_pk_util_free_encoding_ctx): New. * cipher/ecc-curves.c (_gcry_ecc_fill_in_curve): Make curve init optional. * src/g10lib.h (GCC_ATTR_SENTINEL): New. * tests/basic.c (check_pubkey_sign): Print the algo name. (main): Add option --pubkey. Signed-off-by: Werner Koch <wk@gnupg.org>
-rw-r--r--cipher/dsa.c134
-rw-r--r--cipher/ecc-curves.c29
-rw-r--r--cipher/ecc.c192
-rw-r--r--cipher/elgamal.c103
-rw-r--r--cipher/pubkey-internal.h14
-rw-r--r--cipher/pubkey-util.c767
-rw-r--r--cipher/pubkey.c670
-rw-r--r--cipher/rsa.c99
-rw-r--r--src/cipher-proto.h11
-rw-r--r--src/g10lib.h7
-rw-r--r--tests/basic.c14
11 files changed, 1198 insertions, 842 deletions
diff --git a/cipher/dsa.c b/cipher/dsa.c
index d319f732..deeb1132 100644
--- a/cipher/dsa.c
+++ b/cipher/dsa.c
@@ -58,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"
@@ -109,6 +117,8 @@ 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 int 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;
@@ -976,56 +986,95 @@ dsa_sign (int algo, gcry_sexp_t *r_result, gcry_mpi_t data, gcry_mpi_t *skey,
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,
- int flags, int hashalgo)
+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;
+ 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);
- (void)algo;
- (void)cmp;
- (void)opaquev;
- (void)flags;
- (void)hashalgo;
+ /* Extract the signature value. */
+ rc = _gcry_pk_util_preparse_sigval (s_sig, dsa_names, &l1, NULL);
+ if (rc)
+ goto leave;
+ rc = _gcry_pk_util_extract_mpis (l1, "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_pk_util_extract_mpis (s_keyparms, "pqgy",
+ &pk.p, &pk.q, &pk.g, &pk.y, NULL);
+ if (rc)
+ return rc;
+ if (DBG_CIPHER)
{
- pk.p = pkey[0];
- pk.q = pkey[1];
- pk.g = pkey[2];
- pk.y = pkey[3];
- if (mpi_is_opaque (hash))
- {
- const void *abuf;
- unsigned int abits, qbits;
- gcry_mpi_t a;
+ 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);
+ }
- qbits = mpi_get_nbits (pk.q);
+ /* Verify the signature. */
+ if (mpi_is_opaque (data))
+ {
+ const void *abuf;
+ unsigned int abits, qbits;
+ gcry_mpi_t a;
- abuf = gcry_mpi_get_opaque (hash, &abits);
- err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, (abits+7)/8, NULL);
- if (!err)
- {
- if (abits > qbits)
- gcry_mpi_rshift (a, a, abits - qbits);
+ qbits = mpi_get_nbits (pk.q);
- if (!verify (data[0], data[1], a, &pk))
- err = GPG_ERR_BAD_SIGNATURE;
- gcry_mpi_release (a);
- }
- }
- else
+ abuf = gcry_mpi_get_opaque (data, &abits);
+ rc = gpg_err_code (gcry_mpi_scan (&a, GCRYMPI_FMT_USG,
+ abuf, (abits+7)/8, NULL));
+ if (!rc)
{
- if (!verify (data[0], data[1], hash, &pk))
- err = GPG_ERR_BAD_SIGNATURE;
+ if (abits > qbits)
+ gcry_mpi_rshift (a, a, abits - qbits);
+
+ if (!verify (sig_r, sig_s, a, &pk))
+ rc = GPG_ERR_BAD_SIGNATURE;
+ gcry_mpi_release (a);
}
}
- return err;
+ else
+ {
+ if (!verify (sig_r, sig_s, data, &pk))
+ rc = GPG_ERR_BAD_SIGNATURE;
+ }
+
+ 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);
+ gcry_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;
}
@@ -1192,13 +1241,6 @@ 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 =
{
GCRY_PK_DSA, { 0, 1 },
diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c
index 449a168e..971dd322 100644
--- a/cipher/ecc-curves.c
+++ b/cipher/ecc-curves.c
@@ -308,7 +308,9 @@ scanval (const char *string)
parameters of the named curve or those of a suitable curve. If
R_NBITS is not NULL, the chosen number of bits is stored there.
NULL may be given for R_CURVE, if the value is not required and for
- example only a quick test for availability is desired. */
+ example only a quick test for availability is desired. Note that
+ the curve fields should be initialized to zero because fields which
+ are not NULL are skipped. */
gpg_err_code_t
_gcry_ecc_fill_in_curve (unsigned int nbits, const char *name,
elliptic_curve_t *curve, unsigned int *r_nbits)
@@ -378,14 +380,22 @@ _gcry_ecc_fill_in_curve (unsigned int nbits, const char *name,
{
curve->model = domain_parms[idx].model;
curve->dialect = domain_parms[idx].dialect;
- curve->p = scanval (domain_parms[idx].p);
- curve->a = scanval (domain_parms[idx].a);
- curve->b = scanval (domain_parms[idx].b);
- curve->n = scanval (domain_parms[idx].n);
- curve->G.x = scanval (domain_parms[idx].g_x);
- curve->G.y = scanval (domain_parms[idx].g_y);
- curve->G.z = mpi_alloc_set_ui (1);
- curve->name = resname;
+ if (!curve->p)
+ curve->p = scanval (domain_parms[idx].p);
+ if (!curve->a)
+ curve->a = scanval (domain_parms[idx].a);
+ if (!curve->b)
+ curve->b = scanval (domain_parms[idx].b);
+ if (!curve->n)
+ curve->n = scanval (domain_parms[idx].n);
+ if (!curve->G.x)
+ curve->G.x = scanval (domain_parms[idx].g_x);
+ if (!curve->G.y)
+ curve->G.y = scanval (domain_parms[idx].g_y);
+ if (!curve->G.z)
+ curve->G.z = mpi_alloc_set_ui (1);
+ if (!curve->name)
+ curve->name = resname;
}
return 0;
@@ -764,6 +774,7 @@ _gcry_ecc_get_param (const char *name, gcry_mpi_t *pkey)
mpi_ec_t ctx;
gcry_mpi_t g_x, g_y;
+ memset (&E, 0, sizeof E);
err = _gcry_ecc_fill_in_curve (0, name, &E, &nbits);
if (err)
return err;
diff --git a/cipher/ecc.c b/cipher/ecc.c
index e3d397a6..20ba1334 100644
--- a/cipher/ecc.c
+++ b/cipher/ecc.c
@@ -65,6 +65,16 @@
#include "ecc-common.h"
+static const char *ecc_names[] =
+ {
+ "ecc",
+ "ecdsa",
+ "ecdh",
+ "eddsa",
+ NULL,
+ };
+
+
/* Registered progress function and its callback value. */
static void (*progress_cb) (void *, const char*, int, int, int);
static void *progress_cb_data;
@@ -84,6 +94,7 @@ static gpg_err_code_t verify_ecdsa (gcry_mpi_t input, ECC_public_key *pkey,
gcry_mpi_t r, gcry_mpi_t s);
static gcry_mpi_t gen_y_2 (gcry_mpi_t x, elliptic_curve_t * base);
+static unsigned int ecc_get_nbits (gcry_sexp_t parms);
@@ -1536,62 +1547,125 @@ ecc_sign (int algo, gcry_sexp_t *r_result, gcry_mpi_t data, gcry_mpi_t *skey,
static gcry_err_code_t
-ecc_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
- int (*cmp)(void *, gcry_mpi_t), void *opaquev,
- int flags, int hashalgo)
+ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
{
- gpg_err_code_t err;
+ gcry_err_code_t rc;
+ struct pk_encoding_ctx ctx;
+ gcry_sexp_t l1 = NULL;
+ char *curvename = NULL;
+ gcry_mpi_t mpi_g = NULL;
+ gcry_mpi_t mpi_q = NULL;
+ gcry_mpi_t sig_r = NULL;
+ gcry_mpi_t sig_s = NULL;
+ gcry_mpi_t data = NULL;
ECC_public_key pk;
+ int sigflags;
- (void)algo;
- (void)cmp;
- (void)opaquev;
+ memset (&pk, 0, sizeof pk);
+ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY,
+ ecc_get_nbits (s_keyparms));
- if (!data[0] || !data[1] || !hash || !pkey[0] || !pkey[1] || !pkey[2]
- || !pkey[3] || !pkey[4] || !pkey[5] )
- return GPG_ERR_BAD_MPI;
+ /* Extract the data. */
+ rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ log_mpidump ("ecc_verify data", data);
- /* FIXME: The setting of model and dialect are crude hacks. We will
- fix that by moving the s-expression parsing from pubkey.c to
- here. */
- pk.E.model = ((flags & PUBKEY_FLAG_EDDSA)
- ? MPI_EC_TWISTEDEDWARDS
- : MPI_EC_WEIERSTRASS);
- pk.E.dialect = ((flags & PUBKEY_FLAG_EDDSA)
- ? ECC_DIALECT_ED25519
- : ECC_DIALECT_STANDARD);
- pk.E.p = pkey[0];
- pk.E.a = pkey[1];
- pk.E.b = pkey[2];
- point_init (&pk.E.G);
- err = _gcry_ecc_os2ec (&pk.E.G, pkey[3]);
- if (err)
+ /*
+ * Extract the signature value.
+ */
+ rc = _gcry_pk_util_preparse_sigval (s_sig, ecc_names, &l1, &sigflags);
+ if (rc)
+ goto leave;
+ rc = _gcry_pk_util_extract_mpis (l1,
+ (sigflags & PUBKEY_FLAG_EDDSA)? "/rs":"rs",
+ &sig_r, &sig_s, NULL);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
{
- point_free (&pk.E.G);
- return err;
+ log_mpidump ("ecc_verify s_r", sig_r);
+ log_mpidump ("ecc_verify s_s", sig_s);
+ }
+ if ((ctx.flags & PUBKEY_FLAG_EDDSA) ^ (sigflags & PUBKEY_FLAG_EDDSA))
+ {
+ rc = GPG_ERR_CONFLICT; /* Inconsistent use of flag/algoname. */
+ goto leave;
}
- pk.E.n = pkey[4];
- if ((flags & PUBKEY_FLAG_EDDSA))
+
+ /*
+ * Extract the key.
+ */
+ rc = _gcry_pk_util_extract_mpis (s_keyparms, "-p?a?b?g?n?/q?",
+ &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n,
+ &mpi_q, NULL);
+ if (rc)
+ goto leave;
+ if (mpi_g)
+ {
+ point_init (&pk.E.G);
+ rc = _gcry_ecc_os2ec (&pk.E.G, mpi_g);
+ if (rc)
+ goto leave;
+ }
+ /* Add missing parameters using the optional curve parameter. */
+ gcry_sexp_release (l1);
+ l1 = gcry_sexp_find_token (s_keyparms, "curve", 5);
+ if (l1)
+ {
+ curvename = gcry_sexp_nth_string (l1, 1);
+ if (curvename)
+ {
+ rc = _gcry_ecc_fill_in_curve (0, curvename, &pk.E, NULL);
+ if (rc)
+ return rc;
+ }
+ }
+ /* Guess required fields if a curve parameter has not been given.
+ FIXME: This is a crude hacks. We need to fix that. */
+ if (!curvename)
{
- pk.Q.x = NULL;
- pk.Q.y = NULL;
- pk.Q.z = NULL;
+ pk.E.model = ((sigflags & PUBKEY_FLAG_EDDSA)
+ ? MPI_EC_TWISTEDEDWARDS
+ : MPI_EC_WEIERSTRASS);
+ pk.E.dialect = ((sigflags & PUBKEY_FLAG_EDDSA)
+ ? ECC_DIALECT_ED25519
+ : ECC_DIALECT_STANDARD);
+ }
- err = verify_eddsa (hash, &pk, data[0], data[1], hashalgo, pkey[5]);
+ if (DBG_CIPHER)
+ {
+ log_debug ("ecc_verify info: %s/%s\n",
+ _gcry_ecc_model2str (pk.E.model),
+ _gcry_ecc_dialect2str (pk.E.dialect));
+ if (pk.E.name)
+ log_debug ("ecc_verify name: %s\n", pk.E.name);
+ log_printmpi ("ecc_verify p", pk.E.p);
+ log_printmpi ("ecc_verify a", pk.E.a);
+ log_printmpi ("ecc_verify b", pk.E.b);
+ log_printpnt ("ecc_verify g", &pk.E.G, NULL);
+ log_printmpi ("ecc_verify n", pk.E.n);
+ log_printmpi ("ecc_verify q", mpi_q);
+ }
+
+
+ /*
+ * Verify the signature.
+ */
+ if ((sigflags & PUBKEY_FLAG_EDDSA))
+ {
+ rc = verify_eddsa (data, &pk, sig_r, sig_s, ctx.hash_algo, mpi_q);
}
else
{
point_init (&pk.Q);
- err = _gcry_ecc_os2ec (&pk.Q, pkey[5]);
- if (err)
- {
- point_free (&pk.E.G);
- point_free (&pk.Q);
- return err;
- }
+ rc = _gcry_ecc_os2ec (&pk.Q, mpi_q);
+ if (rc)
+ goto leave;
- if (mpi_is_opaque (hash))
+ if (mpi_is_opaque (data))
{
const void *abuf;
unsigned int abits, qbits;
@@ -1599,24 +1673,39 @@ ecc_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
qbits = mpi_get_nbits (pk.E.n);
- abuf = gcry_mpi_get_opaque (hash, &abits);
- err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, (abits+7)/8, NULL);
- if (!err)
+ abuf = gcry_mpi_get_opaque (data, &abits);
+ rc = gpg_err_code (gcry_mpi_scan (&a, GCRYMPI_FMT_USG,
+ abuf, (abits+7)/8, NULL));
+ if (!rc)
{
if (abits > qbits)
gcry_mpi_rshift (a, a, abits - qbits);
- err = verify_ecdsa (a, &pk, data[0], data[1]);
+ rc = verify_ecdsa (a, &pk, sig_r, sig_s);
gcry_mpi_release (a);
}
}
else
- err = verify_ecdsa (hash, &pk, data[0], data[1]);
+ rc = verify_ecdsa (data, &pk, sig_r, sig_s);
}
+ leave:
+ gcry_mpi_release (pk.E.p);
+ gcry_mpi_release (pk.E.a);
+ gcry_mpi_release (pk.E.b);
point_free (&pk.E.G);
+ gcry_mpi_release (pk.E.n);
point_free (&pk.Q);
- return err;
+ gcry_mpi_release (mpi_g);
+ gcry_mpi_release (data);
+ gcry_mpi_release (sig_r);
+ gcry_mpi_release (sig_s);
+ gcry_free (curvename);
+ gcry_sexp_release (l1);
+ _gcry_pk_util_free_encoding_ctx (&ctx);
+ if (DBG_CIPHER)
+ log_debug ("ecc_verify => %s\n", rc?gpg_strerror (rc):"good");
+ return rc;
}
@@ -2125,15 +2214,6 @@ run_selftests (int algo, int extended, selftest_report_func_t report)
-static const char *ecc_names[] =
- {
- "ecc",
- "ecdsa",
- "ecdh",
- "eddsa",
- NULL,
- };
-
gcry_pk_spec_t _gcry_pubkey_spec_ecc =
{
GCRY_PK_ECC, { 0, 0 },
diff --git a/cipher/elgamal.c b/cipher/elgamal.c
index 9a74c54e..b82e83f0 100644
--- a/cipher/elgamal.c
+++ b/cipher/elgamal.c
@@ -50,6 +50,15 @@ typedef struct
} ELG_secret_key;
+static const char *elg_names[] =
+ {
+ "elg",
+ "openpgp-elg",
+ "openpgp-elg-sig",
+ NULL,
+ };
+
+
static int test_keys (ELG_secret_key *sk, unsigned int nbits, int nodie);
static gcry_mpi_t gen_k (gcry_mpi_t p, int small_k);
static void generate (ELG_secret_key *sk, unsigned nbits, gcry_mpi_t **factors);
@@ -62,6 +71,7 @@ static void sign (gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input,
ELG_secret_key *skey);
static int verify (gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input,
ELG_public_key *pkey);
+static unsigned int elg_get_nbits (gcry_sexp_t parms);
static void (*progress_cb) (void *, const char *, int, int, int);
@@ -880,35 +890,72 @@ elg_sign (int algo, gcry_sexp_t *r_result, gcry_mpi_t data, gcry_mpi_t *skey,
static gcry_err_code_t
-elg_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
- int (*cmp) (void *, gcry_mpi_t), void *opaquev,
- int flags, int hashalgo)
+elg_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;
- ELG_public_key pk;
-
- (void)algo;
- (void)cmp;
- (void)opaquev;
- (void)flags;
- (void)hashalgo;
+ 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;
+ ELG_public_key pk = { NULL, NULL, NULL };
+
+ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY,
+ elg_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 ("elg_verify data", data);
+ if (mpi_is_opaque (data))
+ {
+ rc = GPG_ERR_INV_DATA;
+ goto leave;
+ }
- if (mpi_is_opaque (hash))
- return GPG_ERR_INV_DATA;
+ /* Extract the signature value. */
+ rc = _gcry_pk_util_preparse_sigval (s_sig, elg_names, &l1, NULL);
+ if (rc)
+ goto leave;
+ rc = _gcry_pk_util_extract_mpis (l1, "rs", &sig_r, &sig_s, NULL);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ {
+ log_mpidump ("elg_verify s_r", sig_r);
+ log_mpidump ("elg_verify s_s", sig_s);
+ }
- if ((! data[0]) || (! data[1]) || (! hash)
- || (! pkey[0]) || (! pkey[1]) || (! pkey[2]))
- err = GPG_ERR_BAD_MPI;
- else
+ /* Extract the key. */
+ rc = _gcry_pk_util_extract_mpis (s_keyparms, "pgy",
+ &pk.p, &pk.g, &pk.y, NULL);
+ if (rc)
+ return rc;
+ if (DBG_CIPHER)
{
- pk.p = pkey[0];
- pk.g = pkey[1];
- pk.y = pkey[2];
- if (! verify (data[0], data[1], hash, &pk))
- err = GPG_ERR_BAD_SIGNATURE;
+ log_mpidump ("elg_verify p", pk.p);
+ log_mpidump ("elg_verify g", pk.g);
+ log_mpidump ("elg_verify y", pk.y);
}
- return err;
+ /* Verify the signature. */
+ if (!verify (sig_r, sig_s, data, &pk))
+ rc = GPG_ERR_BAD_SIGNATURE;
+
+ leave:
+ gcry_mpi_release (pk.p);
+ gcry_mpi_release (pk.g);
+ gcry_mpi_release (pk.y);
+ gcry_mpi_release (data);
+ gcry_mpi_release (sig_r);
+ gcry_mpi_release (sig_s);
+ gcry_sexp_release (l1);
+ _gcry_pk_util_free_encoding_ctx (&ctx);
+ if (DBG_CIPHER)
+ log_debug ("elg_verify => %s\n", rc?gpg_strerror (rc):"good");
+ return rc;
}
@@ -942,15 +989,7 @@ elg_get_nbits (gcry_sexp_t parms)
}
-static const char *elg_names[] =
- {
- "elg",
- "openpgp-elg",
- "openpgp-elg-sig",
- NULL,
- };
-
-
+
gcry_pk_spec_t _gcry_pubkey_spec_elg =
{
GCRY_PK_ELG, { 0, 0 },
diff --git a/cipher/pubkey-internal.h b/cipher/pubkey-internal.h
index 0b20c7dc..3bed609a 100644
--- a/cipher/pubkey-internal.h
+++ b/cipher/pubkey-internal.h
@@ -25,6 +25,20 @@ gpg_err_code_t _gcry_pk_util_get_nbits (gcry_sexp_t list,
unsigned int *r_nbits);
gpg_err_code_t _gcry_pk_util_get_rsa_use_e (gcry_sexp_t list,
unsigned long *r_e);
+gpg_err_code_t _gcry_pk_util_extract_mpis (gcry_sexp_t sexp,
+ const char *list, ...)
+ GCC_ATTR_SENTINEL(0);
+gpg_err_code_t _gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig,
+ const char **algo_names,
+ gcry_sexp_t *r_parms,
+ int *r_eccflags);
+void _gcry_pk_util_init_encoding_ctx (struct pk_encoding_ctx *ctx,
+ enum pk_operation op,
+ unsigned int nbits);
+void _gcry_pk_util_free_encoding_ctx (struct pk_encoding_ctx *ctx);
+gcry_err_code_t _gcry_pk_util_data_to_mpi (gcry_sexp_t input,
+ gcry_mpi_t *ret_mpi,
+ struct pk_encoding_ctx *ctx);
diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c
index ef0ef441..debe6ca6 100644
--- a/cipher/pubkey-util.c
+++ b/cipher/pubkey-util.c
@@ -30,6 +30,21 @@
#include "pubkey-internal.h"
+/* Callback for the pubkey algorithm code to verify PSS signatures.
+ OPAQUE is the data provided by the actual caller. The meaning of
+ TMP depends on the actual algorithm (but there is only RSA); now
+ for RSA it is the output of running the public key function on the
+ input. */
+static int
+pss_verify_cmp (void *opaque, gcry_mpi_t tmp)
+{
+ struct pk_encoding_ctx *ctx = opaque;
+ gcry_mpi_t hash = ctx->verify_arg;
+
+ return _gcry_rsa_pss_verify (hash, tmp, ctx->nbits - 1,
+ ctx->hash_algo, ctx->saltlen);
+}
+
/* Get the "nbits" parameter from an s-expression of the format:
@@ -125,3 +140,755 @@ _gcry_pk_util_get_rsa_use_e (gcry_sexp_t list, unsigned long *r_e)
gcry_sexp_release (list);
return 0;
}
+
+
+/* Extract MPIs from an s-expression using a list of one letter
+ * parameters. The names of these parameters are given by the string
+ * LIST. Some special characters may be given to control the
+ * conversion:
+ *
+ * + :: Switch to unsigned integer format (default).
+ * - :: Switch to standard signed format.
+ * / :: Switch to opaque format.
+ * ? :: The previous parameter is optional.
+ *
+ * For each parameter name a pointer to an MPI variable is expected
+ * and finally a NULL is expected. Example:
+ *
+ * _gcry_pk_util_extract_mpis (key, "n/x+ed", &mpi_n, &mpi_x, &mpi_e, NULL)
+ *
+ * This stores the parameter "N" from KEY as an unsigned MPI into
+ * MPI_N, the parameter "X" as an opaque MPI into MPI_X, and the
+ * parameter "E" again as an unsigned MPI into MPI_E.
+ *
+ * The function returns NULL on success. On error an error code is
+ * returned and and the passed MPIs have no defined value.
+ */
+gpg_err_code_t
+_gcry_pk_util_extract_mpis (gcry_sexp_t sexp, const char *list, ...)
+{
+ va_list arg_ptr;
+ const char *s;
+ gcry_mpi_t *array[10];
+ int idx;
+ gcry_sexp_t l1;
+ enum gcry_mpi_format mpifmt = GCRYMPI_FMT_USG;
+
+ /* First copy all the args into an array. This is required so that
+ we are able to release already allocated MPIs if later an error
+ was found. */
+ va_start (arg_ptr, list) ;
+ for (s=list, idx=0; *s && idx < DIM (array); s++)
+ {
+ if (*s == '+' || *s == '-' || *s == '/' || *s == '?')
+ ;
+ else
+ {
+ array[idx] = va_arg (arg_ptr, gcry_mpi_t *);
+ if (!array[idx])
+ {
+ va_end (arg_ptr);
+ return GPG_ERR_INTERNAL; /* NULL pointer given. */
+ }
+ idx++;
+ }
+ }
+ if (*s)
+ {
+ va_end (arg_ptr);
+ return GPG_ERR_INTERNAL; /* Too many list elements. */
+ }
+ if (va_arg (arg_ptr, gcry_mpi_t *))
+ {
+ va_end (arg_ptr);
+ return GPG_ERR_INTERNAL; /* Not enough list elemends. */
+ }
+ va_end (arg_ptr);
+
+ /* Now extract all parameters. */
+ for (s=list, idx=0; *s; s++)
+ {
+ if (*s == '+')
+ mpifmt = GCRYMPI_FMT_USG;
+ else if (*s == '-')
+ mpifmt = GCRYMPI_FMT_STD;
+ else if (*s == '/')
+ mpifmt = GCRYMPI_FMT_HEX; /* Used to indicate opaque. */
+ else if (*s == '?')
+ ; /* Only used via lookahead. */
+ else
+ {
+ l1 = gcry_sexp_find_token (sexp, s, 1);
+ if (!l1 && s[1] == '?')
+ *array[idx] = NULL; /* Optional element not found. */
+ else if (!l1)
+ {
+ while (idx--)
+ gcry_mpi_release (*array[idx]);
+ return GPG_ERR_NO_OBJ; /* List element not found. */
+ }
+ else
+ {
+ if (mpifmt == GCRYMPI_FMT_HEX)
+ *array[idx] = _gcry_sexp_nth_opaque_mpi (l1, 1);
+ else
+ *array[idx] = gcry_sexp_nth_mpi (l1, 1, mpifmt);
+ gcry_sexp_release (l1);
+ if (!*array[idx])
+ {
+ while (idx--)
+ gcry_mpi_release (*array[idx]);
+ return GPG_ERR_INV_OBJ; /* Conversion failed. */
+ }
+ }
+ idx++;
+ }
+ }
+
+ return 0;
+}
+
+
+/* Parse a "sig_val s-expression and store the inner parameter list at
+ R_PARMS. ALGO_NAMES is used to verify that the algorithm in
+ "sig-val" is valid. Returns 0 on success and stores a new list at
+ R_PARMS which must be freed by the caller. On error R_PARMS is set
+ to NULL and an error code returned. If R_ECCFLAGS is not NULL flag
+ values are set into it; as of now they are only used with ecc
+ algorithms. */
+gpg_err_code_t
+_gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, const char **algo_names,
+ gcry_sexp_t *r_parms, int *r_eccflags)
+{
+ gpg_err_code_t rc;
+ gcry_sexp_t l1 = NULL;
+ gcry_sexp_t l2 = NULL;
+ char *name = NULL;
+ int i;
+
+ *r_parms = NULL;
+ if (r_eccflags)
+ *r_eccflags = 0;
+
+ /* Extract the signature value. */
+ l1 = gcry_sexp_find_token (s_sig, "sig-val", 0);
+ if (!l1)
+ {
+ rc = GPG_ERR_INV_OBJ; /* Does not contain a signature value object. */
+ goto leave;
+ }
+
+ l2 = gcry_sexp_nth (l1, 1);
+ if (!l2)
+ {
+ rc = GPG_ERR_NO_OBJ; /* No cadr for the sig object. */
+ goto leave;
+ }
+ name = _gcry_sexp_nth_string (l2, 0);
+ if (!name)
+ {
+ rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
+ goto leave;
+ }
+ else if (!strcmp (name, "flags"))
+ {
+ /* Skip a "flags" parameter and look again for the algorithm
+ name. This is not used but here just for the sake of
+ consistent S-expressions we need to handle it. */
+ gcry_sexp_release (l2);
+ l2 = gcry_sexp_nth (l1, 2);
+ if (!l2)
+ {
+ rc = GPG_ERR_INV_OBJ;
+ goto leave;
+ }
+ gcry_free (name);
+ name = _gcry_sexp_nth_string (l2, 0);
+ if (!name)
+ {
+ rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
+ goto leave;
+ }
+ }
+
+ for (i=0; algo_names[i]; i++)
+ if (!stricmp (name, algo_names[i]))
+ break;
+ if (!algo_names[i])
+ {
+ rc = GPG_ERR_CONFLICT; /* "sig-val" uses an unexpected algo. */
+ goto leave;
+ }
+ if (r_eccflags)
+ {
+ if (!strcmp (name, "eddsa"))
+ *r_eccflags = PUBKEY_FLAG_EDDSA;
+ }
+
+ *r_parms = l2;
+ l2 = NULL;
+ rc = 0;
+
+ leave:
+ gcry_free (name);
+ gcry_sexp_release (l2);
+ gcry_sexp_release (l1);
+ return rc;
+}
+
+/* Initialize an encoding context. */
+void
+_gcry_pk_util_init_encoding_ctx (struct pk_encoding_ctx *ctx,
+ enum pk_operation op,
+ unsigned int nbits)
+{
+ ctx->op = op;
+ ctx->nbits = nbits;
+ ctx->encoding = PUBKEY_ENC_UNKNOWN;
+ ctx->flags = 0;
+ ctx->hash_algo = GCRY_MD_SHA1;
+ ctx->label = NULL;
+ ctx->labellen = 0;
+ ctx->saltlen = 20;
+ ctx->verify_cmp = NULL;
+ ctx->verify_arg = NULL;
+}
+
+/* Free a context initialzied by _gcry_pk_util_init_encoding_ctx. */
+void
+_gcry_pk_util_free_encoding_ctx (struct pk_encoding_ctx *ctx)
+{
+ gcry_free (ctx->label);
+}
+
+
+static inline int
+get_hash_algo (const char *s, size_t n)
+{
+ static const struct { const char *name; int algo; } hashnames[] = {
+ { "sha1", GCRY_MD_SHA1 },
+ { "md5", GCRY_MD_MD5 },
+ { "sha256", GCRY_MD_SHA256 },
+ { "ripemd160", GCRY_MD_RMD160 },
+ { "rmd160", GCRY_MD_RMD160 },
+ { "sha384", GCRY_MD_SHA384 },
+ { "sha512", GCRY_MD_SHA512 },
+ { "sha224", GCRY_MD_SHA224 },
+ { "md2", GCRY_MD_MD2 },
+ { "md4", GCRY_MD_MD4 },
+ { "tiger", GCRY_MD_TIGER },
+ { "haval", GCRY_MD_HAVAL },
+ { NULL, 0 }
+ };
+ int algo;
+ int i;
+
+ for (i=0; hashnames[i].name; i++)
+ {
+ if ( strlen (hashnames[i].name) == n
+ && !memcmp (hashnames[i].name, s, n))
+ break;
+ }
+ if (hashnames[i].name)
+ algo = hashnames[i].algo;
+ else
+ {
+ /* In case of not listed or dynamically allocated hash
+ algorithm we fall back to this somewhat slower
+ method. Further, it also allows to use OIDs as
+ algorithm names. */
+ char *tmpname;
+
+ tmpname = gcry_malloc (n+1);
+ if (!tmpname)
+ algo = 0; /* Out of core - silently give up. */
+ else
+ {
+ memcpy (tmpname, s, n);
+ tmpname[n] = 0;
+ algo = gcry_md_map_name (tmpname);
+ gcry_free (tmpname);
+ }
+ }
+ return algo;
+}
+
+
+/* Take the hash value and convert into an MPI, suitable 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 [raw, direct, pkcs1, oaep, pss, no-blinding, rfc6979, eddsa])]
+ [(hash <algo> <value>)]
+ [(value <text>)]
+ [(hash-algo <algo>)]
+ [(label <label>)]
+ [(salt-length <length>)]
+ [(random-override <data>)]
+ )
+
+ Either the VALUE or the HASH element must be present for use
+ with signatures. VALUE is used for encryption.
+
+ HASH-ALGO is specific to OAEP and EDDSA.
+
+ LABEL is specific to OAEP.
+
+ SALT-LENGTH is for PSS.
+
+ RANDOM-OVERRIDE is used to replace random nonces for regression
+ testing. */
+gcry_err_code_t
+_gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
+ struct pk_encoding_ctx *ctx)
+{
+ gcry_err_code_t rc = 0;
+ gcry_sexp_t ldata, lhash, lvalue;
+ int i;
+ size_t n;
+ const char *s;
+ int unknown_flag = 0;
+ int parsed_flags = 0;
+ int explicit_raw = 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 ? GPG_ERR_NO_ERROR : GPG_ERR_INV_OBJ;
+ }
+
+ /* see whether there is a flags object */
+ {
+ gcry_sexp_t 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 == 7 && !memcmp (s, "rfc6979", 7))
+ parsed_flags |= PUBKEY_FLAG_RFC6979;
+ else if (n == 5 && !memcmp (s, "eddsa", 5))
+ {
+ ctx->encoding = PUBKEY_ENC_RAW;
+ parsed_flags |= PUBKEY_FLAG_EDDSA;
+ }
+ else if ( n == 3 && !memcmp (s, "raw", 3)
+ && ctx->encoding == PUBKEY_ENC_UNKNOWN)
+ {
+ 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;
+ parsed_flags |= PUBKEY_FLAG_FIXEDLEN;
+ }
+ else if ( n == 4 && !memcmp (s, "oaep", 4)
+ && ctx->encoding == PUBKEY_ENC_UNKNOWN)
+ {
+ ctx->encoding = PUBKEY_ENC_OAEP;
+ parsed_flags |= PUBKEY_FLAG_FIXEDLEN;
+ }
+ else if ( n == 3 && !memcmp (s, "pss", 3)
+ && ctx->encoding == PUBKEY_ENC_UNKNOWN)
+ {
+ ctx->encoding = PUBKEY_ENC_PSS;
+ parsed_flags |= PUBKEY_FLAG_FIXEDLEN;
+ }
+ else if (n == 11 && ! memcmp (s, "no-blinding", 11))
+ parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
+ else
+ unknown_flag = 1;
+ }
+ gcry_sexp_release (lflags);
+ }
+ }
+
+ if (ctx->encoding == PUBKEY_ENC_UNKNOWN)
+ ctx->encoding = PUBKEY_ENC_RAW; /* 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 = GPG_ERR_INV_OBJ; /* none or both given */
+ else if (unknown_flag)
+ rc = GPG_ERR_INV_FLAG;
+ else if (ctx->encoding == PUBKEY_ENC_RAW
+ && (parsed_flags & PUBKEY_FLAG_EDDSA))
+ {
+ /* Prepare for EdDSA. */
+ gcry_sexp_t list;
+ void *value;
+ size_t valuelen;
+
+ if (!lvalue)
+ {
+ rc = GPG_ERR_INV_OBJ;
+ goto leave;
+ }
+ /* Get HASH-ALGO. */
+ list = gcry_sexp_find_token (ldata, "hash-algo", 0);
+ if (list)
+ {
+ s = gcry_sexp_nth_data (list, 1, &n);
+ if (!s)
+ rc = GPG_ERR_NO_OBJ;
+ else
+ {
+ ctx->hash_algo = get_hash_algo (s, n);
+ if (!ctx->hash_algo)
+ rc = GPG_ERR_DIGEST_ALGO;
+ }
+ gcry_sexp_release (list);
+ }
+ else
+ rc = GPG_ERR_INV_OBJ;
+ if (rc)
+ goto leave;
+
+ /* Get VALUE. */
+ value = gcry_sexp_nth_buffer (lvalue, 1, &valuelen);
+ if (!value)
+ {
+ /* We assume that a zero length message is meant by
+ "(value)". This is commonly used by test vectors. Note
+ that S-expression do not allow zero length items. */
+ valuelen = 0;
+ value = gcry_malloc (1);
+ if (!value)
+ rc = gpg_err_code_from_syserror ();
+ }
+ else if ((valuelen * 8) < valuelen)
+ {
+ gcry_free (value);
+ rc = GPG_ERR_TOO_LARGE;
+ }
+ if (rc)
+ goto leave;
+
+ /* Note that mpi_set_opaque takes ownership of VALUE. */
+ *ret_mpi = gcry_mpi_set_opaque (NULL, value, valuelen*8);
+ }
+ 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;
+ }
+ else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lvalue
+ && ctx->op == PUBKEY_OP_ENCRYPT)
+ {
+ const void * value;
+ size_t valuelen;
+ gcry_sexp_t list;
+ void *random_override = NULL;
+ size_t random_override_len = 0;
+
+ if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
+ rc = GPG_ERR_INV_OBJ;
+ else
+ {
+ /* Get optional RANDOM-OVERRIDE. */
+ list = gcry_sexp_find_token (ldata, "random-override", 0);
+ if (list)
+ {
+ s = gcry_sexp_nth_data (list, 1, &n);
+ if (!s)
+ rc = GPG_ERR_NO_OBJ;
+ else if (n > 0)
+ {
+ random_override = gcry_malloc (n);
+ if (!random_override)
+ rc = gpg_err_code_from_syserror ();
+ else
+ {
+ memcpy (random_override, s, n);
+ random_override_len = n;
+ }
+ }
+ gcry_sexp_release (list);
+ if (rc)
+ goto leave;
+ }
+
+ rc = _gcry_rsa_pkcs1_encode_for_enc (ret_mpi, ctx->nbits,
+ value, valuelen,
+ random_override,
+ random_override_len);
+ gcry_free (random_override);
+ }
+ }
+ else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lhash
+ && (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY))
+ {
+ 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
+ {
+ const 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_data (lhash, 2, &valuelen))
+ || !valuelen )
+ rc = GPG_ERR_INV_OBJ;
+ else
+ rc = _gcry_rsa_pkcs1_encode_for_sig (ret_mpi, ctx->nbits,
+ value, valuelen,
+ ctx->hash_algo);
+ }
+ }
+ else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue
+ && ctx->op == PUBKEY_OP_ENCRYPT)
+ {
+ const void * value;
+ size_t valuelen;
+
+ if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
+ rc = GPG_ERR_INV_OBJ;
+ else
+ {
+ gcry_sexp_t list;
+ void *random_override = NULL;
+ size_t random_override_len = 0;
+
+ /* Get HASH-ALGO. */
+ list = gcry_sexp_find_token (ldata, "hash-algo", 0);
+ if (list)
+ {
+ s = gcry_sexp_nth_data (list, 1, &n);
+ if (!s)
+ rc = GPG_ERR_NO_OBJ;
+ else
+ {
+ ctx->hash_algo = get_hash_algo (s, n);
+ if (!ctx->hash_algo)
+ rc = GPG_ERR_DIGEST_ALGO;
+ }
+ gcry_sexp_release (list);
+ if (rc)
+ goto leave;
+ }
+
+ /* Get LABEL. */
+ list = gcry_sexp_find_token (ldata, "label", 0);
+ if (list)
+ {
+ s = gcry_sexp_nth_data (list, 1, &n);
+ if (!s)
+ rc = GPG_ERR_NO_OBJ;
+ else if (n > 0)
+ {
+ ctx->label = gcry_malloc (n);
+ if (!ctx->label)
+ rc = gpg_err_code_from_syserror ();
+ else
+ {
+ memcpy (ctx->label, s, n);
+ ctx->labellen = n;
+ }
+ }
+ gcry_sexp_release (list);
+ if (rc)
+ goto leave;
+ }
+ /* Get optional RANDOM-OVERRIDE. */
+ list = gcry_sexp_find_token (ldata, "random-override", 0);
+ if (list)
+ {
+ s = gcry_sexp_nth_data (list, 1, &n);
+ if (!s)
+ rc = GPG_ERR_NO_OBJ;
+ else if (n > 0)
+ {
+ random_override = gcry_malloc (n);
+ if (!random_override)
+ rc = gpg_err_code_from_syserror ();
+ else
+ {
+ memcpy (random_override, s, n);
+ random_override_len = n;
+ }
+ }
+ gcry_sexp_release (list);
+ if (rc)
+ goto leave;
+ }
+
+ rc = _gcry_rsa_oaep_encode (ret_mpi, ctx->nbits, ctx->hash_algo,
+ value, valuelen,
+ ctx->label, ctx->labellen,
+ random_override, random_override_len);
+
+ gcry_free (random_override);
+ }
+ }
+ else if (ctx->encoding == PUBKEY_ENC_PSS && lhash
+ && ctx->op == PUBKEY_OP_SIGN)
+ {
+ 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
+ {
+ const void * value;
+ size_t valuelen;
+ void *random_override = NULL;
+ size_t random_override_len = 0;
+
+ ctx->hash_algo = get_hash_algo (s, n);
+
+ if (!ctx->hash_algo)
+ rc = GPG_ERR_DIGEST_ALGO;
+ else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen))
+ || !valuelen )
+ rc = GPG_ERR_INV_OBJ;
+ else
+ {
+ gcry_sexp_t list;
+
+ /* Get SALT-LENGTH. */
+ list = gcry_sexp_find_token (ldata, "salt-length", 0);
+ if (list)
+ {
+ s = gcry_sexp_nth_data (list, 1, &n);
+ if (!s)
+ {
+ rc = GPG_ERR_NO_OBJ;
+ goto leave;
+ }
+ ctx->saltlen = (unsigned int)strtoul (s, NULL, 10);
+ gcry_sexp_release (list);
+ }
+
+ /* Get optional RANDOM-OVERRIDE. */
+ list = gcry_sexp_find_token (ldata, "random-override", 0);
+ if (list)
+ {
+ s = gcry_sexp_nth_data (list, 1, &n);
+ if (!s)
+ rc = GPG_ERR_NO_OBJ;
+ else if (n > 0)
+ {
+ random_override = gcry_malloc (n);
+ if (!random_override)
+ rc = gpg_err_code_from_syserror ();
+ else
+ {
+ memcpy (random_override, s, n);
+ random_override_len = n;
+ }
+ }
+ gcry_sexp_release (list);
+ if (rc)
+ goto leave;
+ }
+
+ /* Encode the data. (NBITS-1 is due to 8.1.1, step 1.) */
+ rc = _gcry_rsa_pss_encode (ret_mpi, ctx->nbits - 1,
+ ctx->hash_algo,
+ value, valuelen, ctx->saltlen,
+ random_override, random_override_len);
+
+ gcry_free (random_override);
+ }
+ }
+ }
+ else if (ctx->encoding == PUBKEY_ENC_PSS && lhash
+ && ctx->op == PUBKEY_OP_VERIFY)
+ {
+ 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
+ {
+ ctx->hash_algo = get_hash_algo (s, n);
+
+ if (!ctx->hash_algo)
+ rc = GPG_ERR_DIGEST_ALGO;
+ else
+ {
+ *ret_mpi = gcry_sexp_nth_mpi (lhash, 2, GCRYMPI_FMT_USG);
+ if (!*ret_mpi)
+ rc = GPG_ERR_INV_OBJ;
+ ctx->verify_cmp = pss_verify_cmp;
+ ctx->verify_arg = *ret_mpi;
+ }
+ }
+ }
+ else
+ rc = GPG_ERR_CONFLICT;
+
+ leave:
+ gcry_sexp_release (ldata);
+ gcry_sexp_release (lhash);
+ gcry_sexp_release (lvalue);
+
+ if (!rc)
+ ctx->flags = parsed_flags;
+ else
+ {
+ gcry_free (ctx->label);
+ ctx->label = NULL;
+ }
+
+ return rc;
+}
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index cb2177ba..034b00fa 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -130,6 +130,8 @@ spec_from_sexp (gcry_sexp_t sexp, int want_private,
gcry_pk_spec_t *spec;
*r_spec = NULL;
+ if (r_parms)
+ *r_parms = NULL;
/* Check that the first element is valid. If we are looking for a
public key but a private key was supplied, we allow the use of
@@ -637,88 +639,8 @@ sexp_to_key (gcry_sexp_t sexp, int want_private, int use,
}
-/* Parse SEXP and store the elements into a newly allocated array of
- MPIs which will be stored at RETARRAY. If OPAQUE is set, store the
- MPI as opaque data. */
-static gcry_err_code_t
-sexp_to_sig (gcry_sexp_t sexp, gcry_mpi_t **retarray,
- gcry_pk_spec_t **r_spec, int opaque)
-{
- gcry_err_code_t err = 0;
- gcry_sexp_t list, l2;
- char *name;
- const char *elems;
- gcry_mpi_t *array;
- gcry_pk_spec_t *spec;
-
- /* Check that the first element is valid. */
- list = gcry_sexp_find_token( sexp, "sig-val" , 0 );
- if (!list)
- return GPG_ERR_INV_OBJ; /* Does not contain a signature value object. */
-
- l2 = gcry_sexp_nth (list, 1);
- if (!l2)
- {
- gcry_sexp_release (list);
- return GPG_ERR_NO_OBJ; /* No cadr for the sig object. */
- }
- name = _gcry_sexp_nth_string (l2, 0);
- if (!name)
- {
- gcry_sexp_release (list);
- gcry_sexp_release (l2);
- return GPG_ERR_INV_OBJ; /* Invalid structure of object. */
- }
- else if (!strcmp (name, "flags"))
- {
- /* Skip flags, since they are not used but here just for the
- sake of consistent S-expressions. */
- gcry_free (name);
- gcry_sexp_release (l2);
- l2 = gcry_sexp_nth (list, 2);
- if (!l2)
- {
- gcry_sexp_release (list);
- return GPG_ERR_INV_OBJ;
- }
- name = _gcry_sexp_nth_string (l2, 0);
- }
-
- spec = spec_from_name (name);
- gcry_free (name);
- name = NULL;
-
- if (!spec)
- {
- gcry_sexp_release (l2);
- gcry_sexp_release (list);
- return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
- }
-
- elems = spec->elements_sig;
- array = gcry_calloc (strlen (elems) + 1 , sizeof *array );
- if (!array)
- err = gpg_err_code_from_syserror ();
-
- if (!err)
- err = sexp_elements_extract (list, elems, array, NULL, opaque);
-
- gcry_sexp_release (l2);
- gcry_sexp_release (list);
-
- if (err)
- {
- gcry_free (array);
- }
- else
- {
- *retarray = array;
- *r_spec = spec;
- }
-
- return err;
-}
+/* FIXME: This is a duplicate. */
static inline int
get_hash_algo (const char *s, size_t n)
{
@@ -978,518 +900,6 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_pk_spec_t **r_spec,
}
-/* Callback for the pubkey algorithm code to verify PSS signatures.
- OPAQUE is the data provided by the actual caller. The meaning of
- TMP depends on the actual algorithm (but there is only RSA); now
- for RSA it is the output of running the public key function on the
- input. */
-static int
-pss_verify_cmp (void *opaque, gcry_mpi_t tmp)
-{
- struct pk_encoding_ctx *ctx = opaque;
- gcry_mpi_t hash = ctx->verify_arg;
-
- return _gcry_rsa_pss_verify (hash, tmp, ctx->nbits - 1,
- ctx->hash_algo, ctx->saltlen);
-}
-
-
-/* Take the hash value and convert into an MPI, suitable 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 [raw, direct, pkcs1, oaep, pss, no-blinding, rfc6979, eddsa])]
- [(hash <algo> <value>)]
- [(value <text>)]
- [(hash-algo <algo>)]
- [(label <label>)]
- [(salt-length <length>)]
- [(random-override <data>)]
- )
-
- Either the VALUE or the HASH element must be present for use
- with signatures. VALUE is used for encryption.
-
- HASH-ALGO is specific to OAEP and EDDSA.
-
- LABEL is specific to OAEP.
-
- SALT-LENGTH is for PSS.
-
- RANDOM-OVERRIDE is used to replace random nonces for regression
- testing. */
-static gcry_err_code_t
-sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
- struct pk_encoding_ctx *ctx)
-{
- gcry_err_code_t rc = 0;
- gcry_sexp_t ldata, lhash, lvalue;
- int i;
- size_t n;
- const char *s;
- int unknown_flag = 0;
- int parsed_flags = 0;
- int explicit_raw = 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 ? GPG_ERR_NO_ERROR : GPG_ERR_INV_OBJ;
- }
-
- /* see whether there is a flags object */
- {
- gcry_sexp_t 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 == 7 && !memcmp (s, "rfc6979", 7))
- parsed_flags |= PUBKEY_FLAG_RFC6979;
- else if (n == 5 && !memcmp (s, "eddsa", 5))
- {
- ctx->encoding = PUBKEY_ENC_RAW;
- parsed_flags |= PUBKEY_FLAG_EDDSA;
- }
- else if ( n == 3 && !memcmp (s, "raw", 3)
- && ctx->encoding == PUBKEY_ENC_UNKNOWN)
- {
- 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;
- parsed_flags |= PUBKEY_FLAG_FIXEDLEN;
- }
- else if ( n == 4 && !memcmp (s, "oaep", 4)
- && ctx->encoding == PUBKEY_ENC_UNKNOWN)
- {
- ctx->encoding = PUBKEY_ENC_OAEP;
- parsed_flags |= PUBKEY_FLAG_FIXEDLEN;
- }
- else if ( n == 3 && !memcmp (s, "pss", 3)
- && ctx->encoding == PUBKEY_ENC_UNKNOWN)
- {
- ctx->encoding = PUBKEY_ENC_PSS;
- parsed_flags |= PUBKEY_FLAG_FIXEDLEN;
- }
- else if (n == 11 && ! memcmp (s, "no-blinding", 11))
- parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
- else
- unknown_flag = 1;
- }
- gcry_sexp_release (lflags);
- }
- }
-
- if (ctx->encoding == PUBKEY_ENC_UNKNOWN)
- ctx->encoding = PUBKEY_ENC_RAW; /* 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 = GPG_ERR_INV_OBJ; /* none or both given */
- else if (unknown_flag)
- rc = GPG_ERR_INV_FLAG;
- else if (ctx->encoding == PUBKEY_ENC_RAW
- && (parsed_flags & PUBKEY_FLAG_EDDSA))
- {
- /* Prepare for EdDSA. */
- gcry_sexp_t list;
- void *value;
- size_t valuelen;
-
- if (!lvalue)
- {
- rc = GPG_ERR_INV_OBJ;
- goto leave;
- }
- /* Get HASH-ALGO. */
- list = gcry_sexp_find_token (ldata, "hash-algo", 0);
- if (list)
- {
- s = gcry_sexp_nth_data (list, 1, &n);
- if (!s)
- rc = GPG_ERR_NO_OBJ;
- else
- {
- ctx->hash_algo = get_hash_algo (s, n);
- if (!ctx->hash_algo)
- rc = GPG_ERR_DIGEST_ALGO;
- }
- gcry_sexp_release (list);
- }
- else
- rc = GPG_ERR_INV_OBJ;
- if (rc)
- goto leave;
-
- /* Get VALUE. */
- value = gcry_sexp_nth_buffer (lvalue, 1, &valuelen);
- if (!value)
- {
- /* We assume that a zero length message is meant by
- "(value)". This is commonly used by test vectors. Note
- that S-expression do not allow zero length items. */
- valuelen = 0;
- value = gcry_malloc (1);
- if (!value)
- rc = gpg_err_code_from_syserror ();
- }
- else if ((valuelen * 8) < valuelen)
- {
- gcry_free (value);
- rc = GPG_ERR_TOO_LARGE;
- }
- if (rc)
- goto leave;
-
- /* Note that mpi_set_opaque takes ownership of VALUE. */
- *ret_mpi = gcry_mpi_set_opaque (NULL, value, valuelen*8);
- }
- 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;
- }
- else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lvalue
- && ctx->op == PUBKEY_OP_ENCRYPT)
- {
- const void * value;
- size_t valuelen;
- gcry_sexp_t list;
- void *random_override = NULL;
- size_t random_override_len = 0;
-
- if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
- rc = GPG_ERR_INV_OBJ;
- else
- {
- /* Get optional RANDOM-OVERRIDE. */
- list = gcry_sexp_find_token (ldata, "random-override", 0);
- if (list)
- {
- s = gcry_sexp_nth_data (list, 1, &n);
- if (!s)
- rc = GPG_ERR_NO_OBJ;
- else if (n > 0)
- {
- random_override = gcry_malloc (n);
- if (!random_override)
- rc = gpg_err_code_from_syserror ();
- else
- {
- memcpy (random_override, s, n);
- random_override_len = n;
- }
- }
- gcry_sexp_release (list);
- if (rc)
- goto leave;
- }
-
- rc = _gcry_rsa_pkcs1_encode_for_enc (ret_mpi, ctx->nbits,
- value, valuelen,
- random_override,
- random_override_len);
- gcry_free (random_override);
- }
- }
- else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lhash
- && (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY))
- {
- 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
- {
- const 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_data (lhash, 2, &valuelen))
- || !valuelen )
- rc = GPG_ERR_INV_OBJ;
- else
- rc = _gcry_rsa_pkcs1_encode_for_sig (ret_mpi, ctx->nbits,
- value, valuelen,
- ctx->hash_algo);
- }
- }
- else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue
- && ctx->op == PUBKEY_OP_ENCRYPT)
- {
- const void * value;
- size_t valuelen;
-
- if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
- rc = GPG_ERR_INV_OBJ;
- else
- {
- gcry_sexp_t list;
- void *random_override = NULL;
- size_t random_override_len = 0;
-
- /* Get HASH-ALGO. */
- list = gcry_sexp_find_token (ldata, "hash-algo", 0);
- if (list)
- {
- s = gcry_sexp_nth_data (list, 1, &n);
- if (!s)
- rc = GPG_ERR_NO_OBJ;
- else
- {
- ctx->hash_algo = get_hash_algo (s, n);
- if (!ctx->hash_algo)
- rc = GPG_ERR_DIGEST_ALGO;
- }
- gcry_sexp_release (list);
- if (rc)
- goto leave;
- }
-
- /* Get LABEL. */
- list = gcry_sexp_find_token (ldata, "label", 0);
- if (list)
- {
- s = gcry_sexp_nth_data (list, 1, &n);
- if (!s)
- rc = GPG_ERR_NO_OBJ;
- else if (n > 0)
- {
- ctx->label = gcry_malloc (n);
- if (!ctx->label)
- rc = gpg_err_code_from_syserror ();
- else
- {
- memcpy (ctx->label, s, n);
- ctx->labellen = n;
- }
- }
- gcry_sexp_release (list);
- if (rc)
- goto leave;
- }
- /* Get optional RANDOM-OVERRIDE. */
- list = gcry_sexp_find_token (ldata, "random-override", 0);
- if (list)
- {
- s = gcry_sexp_nth_data (list, 1, &n);
- if (!s)
- rc = GPG_ERR_NO_OBJ;
- else if (n > 0)
- {
- random_override = gcry_malloc (n);
- if (!random_override)
- rc = gpg_err_code_from_syserror ();
- else
- {
- memcpy (random_override, s, n);
- random_override_len = n;
- }
- }
- gcry_sexp_release (list);
- if (rc)
- goto leave;
- }
-
- rc = _gcry_rsa_oaep_encode (ret_mpi, ctx->nbits, ctx->hash_algo,
- value, valuelen,
- ctx->label, ctx->labellen,
- random_override, random_override_len);
-
- gcry_free (random_override);
- }
- }
- else if (ctx->encoding == PUBKEY_ENC_PSS && lhash
- && ctx->op == PUBKEY_OP_SIGN)
- {
- 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
- {
- const void * value;
- size_t valuelen;
- void *random_override = NULL;
- size_t random_override_len = 0;
-
- ctx->hash_algo = get_hash_algo (s, n);
-
- if (!ctx->hash_algo)
- rc = GPG_ERR_DIGEST_ALGO;
- else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen))
- || !valuelen )
- rc = GPG_ERR_INV_OBJ;
- else
- {
- gcry_sexp_t list;
-
- /* Get SALT-LENGTH. */
- list = gcry_sexp_find_token (ldata, "salt-length", 0);
- if (list)
- {
- s = gcry_sexp_nth_data (list, 1, &n);
- if (!s)
- {
- rc = GPG_ERR_NO_OBJ;
- goto leave;
- }
- ctx->saltlen = (unsigned int)strtoul (s, NULL, 10);
- gcry_sexp_release (list);
- }
-
- /* Get optional RANDOM-OVERRIDE. */
- list = gcry_sexp_find_token (ldata, "random-override", 0);
- if (list)
- {
- s = gcry_sexp_nth_data (list, 1, &n);
- if (!s)
- rc = GPG_ERR_NO_OBJ;
- else if (n > 0)
- {
- random_override = gcry_malloc (n);
- if (!random_override)
- rc = gpg_err_code_from_syserror ();
- else
- {
- memcpy (random_override, s, n);
- random_override_len = n;
- }
- }
- gcry_sexp_release (list);
- if (rc)
- goto leave;
- }
-
- /* Encode the data. (NBITS-1 is due to 8.1.1, step 1.) */
- rc = _gcry_rsa_pss_encode (ret_mpi, ctx->nbits - 1,
- ctx->hash_algo,
- value, valuelen, ctx->saltlen,
- random_override, random_override_len);
-
- gcry_free (random_override);
- }
- }
- }
- else if (ctx->encoding == PUBKEY_ENC_PSS && lhash
- && ctx->op == PUBKEY_OP_VERIFY)
- {
- 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
- {
- ctx->hash_algo = get_hash_algo (s, n);
-
- if (!ctx->hash_algo)
- rc = GPG_ERR_DIGEST_ALGO;
- else
- {
- *ret_mpi = gcry_sexp_nth_mpi (lhash, 2, GCRYMPI_FMT_USG);
- if (!*ret_mpi)
- rc = GPG_ERR_INV_OBJ;
- ctx->verify_cmp = pss_verify_cmp;
- ctx->verify_arg = *ret_mpi;
- }
- }
- }
- else
- rc = GPG_ERR_CONFLICT;
-
- leave:
- gcry_sexp_release (ldata);
- gcry_sexp_release (lhash);
- gcry_sexp_release (lvalue);
-
- if (!rc)
- ctx->flags = parsed_flags;
- else
- {
- gcry_free (ctx->label);
- ctx->label = NULL;
- }
-
- return rc;
-}
-
-static void
-init_encoding_ctx (struct pk_encoding_ctx *ctx, enum pk_operation op,
- unsigned int nbits)
-{
- ctx->op = op;
- ctx->nbits = nbits;
- ctx->encoding = PUBKEY_ENC_UNKNOWN;
- ctx->flags = 0;
- ctx->hash_algo = GCRY_MD_SHA1;
- ctx->label = NULL;
- ctx->labellen = 0;
- ctx->saltlen = 20;
- ctx->verify_cmp = NULL;
- ctx->verify_arg = NULL;
-}
-
-
/*
Do a PK encrypt operation
@@ -1502,7 +912,7 @@ init_encoding_ctx (struct pk_encoding_ctx *ctx, enum pk_operation op,
Returns: 0 or an errorcode.
- s_data = See comment for sexp_data_to_mpi
+ s_data = See comment for _gcry_pk_util_data_to_mpi
s_pkey = <key-as-defined-in-sexp_to_key>
r_ciph = (enc-val
(<algo>
@@ -1532,8 +942,8 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
gcry_assert (spec);
/* Get the stuff we want to encrypt. */
- init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, gcry_pk_get_nbits (s_pkey));
- rc = sexp_data_to_mpi (s_data, &data, &ctx);
+ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, gcry_pk_get_nbits (s_pkey));
+ rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
if (rc)
goto leave;
@@ -1622,7 +1032,7 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
if (rc)
goto leave;
- init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, gcry_pk_get_nbits (s_skey));
+ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, gcry_pk_get_nbits (s_skey));
rc = sexp_to_enc (s_data, &data, &spec_enc, &flags, &ctx);
if (rc)
goto leave;
@@ -1691,7 +1101,7 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
other arguments but is always suitable to be passed to
gcry_pk_verify
- s_hash = See comment for sexp_data_to_mpi
+ s_hash = See comment for _gcry-pk_util_data_to_mpi
s_skey = <key-as-defined-in-sexp_to_key>
r_sig = (sig-val
@@ -1726,9 +1136,9 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
/* Get the stuff we want to sign. Note that pk_get_nbits does also
work on a private key. We don't need the number of bits for ECC
here, thus set it to 0 so that we don't need to parse it. */
- init_encoding_ctx (&ctx, PUBKEY_OP_SIGN,
+ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN,
is_ecc? 0 : gcry_pk_get_nbits (s_skey));
- rc = sexp_data_to_mpi (s_hash, &hash, &ctx);
+ rc = _gcry_pk_util_data_to_mpi (s_hash, &hash, &ctx);
if (rc)
goto leave;
@@ -1786,70 +1196,20 @@ gcry_error_t
gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey)
{
gcry_err_code_t rc;
- gcry_pk_spec_t *spec = NULL;
- gcry_pk_spec_t *spec_sig = NULL;
- gcry_mpi_t *pkey = NULL;
- gcry_mpi_t hash = NULL;
- gcry_mpi_t *sig = NULL;
- struct pk_encoding_ctx ctx;
- int i;
-
- rc = sexp_to_key (s_pkey, 0, GCRY_PK_USAGE_SIGN, NULL,
- &pkey, &spec, NULL);
- if (rc)
- goto leave;
-
- /* Get the stuff we want to verify. */
- init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, gcry_pk_get_nbits (s_pkey));
- rc = sexp_data_to_mpi (s_hash, &hash, &ctx);
- if (rc)
- goto leave;
+ gcry_pk_spec_t *spec;
+ gcry_sexp_t keyparms;
- /* Get the signature. */
- rc = sexp_to_sig (s_sig, &sig, &spec_sig,
- !!(ctx.flags & PUBKEY_FLAG_EDDSA));
+ rc = spec_from_sexp (s_pkey, 0, &spec, &keyparms);
if (rc)
goto leave;
- /* Fixme: Check that the algorithm of S_SIG is compatible to the one
- of S_PKEY. */
-
- if (spec->algo != spec_sig->algo)
- {
- rc = GPG_ERR_CONFLICT;
- goto leave;
- }
-
- if (DBG_CIPHER && !fips_mode ())
- {
- log_debug ("gcry_pk_verify: algo=%d\n", spec->algo);
- for (i = 0; i < pubkey_get_npkey (spec->algo); i++)
- log_mpidump (" pkey", pkey[i]);
- for (i = 0; i < pubkey_get_nsig (spec->algo); i++)
- log_mpidump (" sig", sig[i]);
- log_mpidump (" hash", hash);
- }
if (spec->verify)
- rc = spec->verify (spec->algo, hash, sig, pkey,
- ctx.verify_cmp, &ctx, ctx.flags, ctx.hash_algo);
+ rc = spec->verify (s_sig, s_hash, keyparms);
else
rc = GPG_ERR_NOT_IMPLEMENTED;
-
leave:
- if (pkey)
- {
- release_mpi_array (pkey);
- gcry_free (pkey);
- }
- if (sig)
- {
- release_mpi_array (sig);
- gcry_free (sig);
- }
- if (hash)
- mpi_free (hash);
-
+ gcry_sexp_release (keyparms);
return gcry_error (rc);
}
diff --git a/cipher/rsa.c b/cipher/rsa.c
index c400718b..39effcba 100644
--- a/cipher/rsa.c
+++ b/cipher/rsa.c
@@ -53,6 +53,15 @@ typedef struct
} RSA_secret_key;
+static const char *rsa_names[] =
+ {
+ "rsa",
+ "openpgp-rsa",
+ "oid.1.2.840.113549.1.1.1",
+ NULL,
+ };
+
+
/* A sample 1024 bit RSA key used for the selftests. */
static const char sample_secret_key[] =
"(private-key"
@@ -89,6 +98,7 @@ static int test_keys (RSA_secret_key *sk, unsigned nbits);
static int check_secret_key (RSA_secret_key *sk);
static void public (gcry_mpi_t output, gcry_mpi_t input, RSA_public_key *skey);
static void secret (gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey);
+static unsigned int rsa_get_nbits (gcry_sexp_t parms);
/* Check that a freshly generated key actually works. Returns 0 on success. */
@@ -1049,40 +1059,71 @@ rsa_sign (int algo, gcry_sexp_t *r_result, gcry_mpi_t data, gcry_mpi_t *skey,
static gcry_err_code_t
-rsa_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
- int (*cmp) (void *opaque, gcry_mpi_t tmp), void *opaquev,
- int flags, int hashalgo)
+rsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
{
- RSA_public_key pk;
- gcry_mpi_t result;
gcry_err_code_t rc;
+ struct pk_encoding_ctx ctx;
+ gcry_sexp_t l1 = NULL;
+ gcry_mpi_t sig = NULL;
+ gcry_mpi_t data = NULL;
+ RSA_public_key pk = { NULL, NULL };
+ gcry_mpi_t result = NULL;
+
+ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY,
+ rsa_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 ("rsa_verify data", data);
+ if (mpi_is_opaque (data))
+ {
+ rc = GPG_ERR_INV_DATA;
+ goto leave;
+ }
- (void)algo;
- (void)cmp;
- (void)opaquev;
- (void)flags;
- (void)hashalgo;
-
- if (mpi_is_opaque (hash))
- return GPG_ERR_INV_DATA;
+ /* Extract the signature value. */
+ rc = _gcry_pk_util_preparse_sigval (s_sig, rsa_names, &l1, NULL);
+ if (rc)
+ goto leave;
+ rc = _gcry_pk_util_extract_mpis (l1, "s", &sig, NULL);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ log_mpidump ("rsa_verify sig", sig);
- pk.n = pkey[0];
- pk.e = pkey[1];
- result = gcry_mpi_new ( 160 );
- public( result, data[0], &pk );
-#ifdef IS_DEVELOPMENT_VERSION
+ /* Extract the key. */
+ rc = _gcry_pk_util_extract_mpis (s_keyparms, "ne", &pk.n, &pk.e, NULL);
+ if (rc)
+ return rc;
if (DBG_CIPHER)
{
- log_mpidump ("rsa verify result", result );
- log_mpidump (" hash", hash );
+ log_mpidump ("rsa_verify n", pk.n);
+ log_mpidump ("rsa_verify e", pk.e);
}
-#endif /*IS_DEVELOPMENT_VERSION*/
- if (cmp)
- rc = (*cmp) (opaquev, result);
+
+ /* Do RSA computation and compare. */
+ result = gcry_mpi_new (0);
+ public (result, sig, &pk);
+ if (DBG_CIPHER)
+ log_mpidump ("rsa_verify cmp", result);
+ if (ctx.verify_cmp)
+ rc = ctx.verify_cmp (&ctx, result);
else
- rc = mpi_cmp (result, hash) ? GPG_ERR_BAD_SIGNATURE : GPG_ERR_NO_ERROR;
- gcry_mpi_release (result);
+ rc = mpi_cmp (result, data) ? GPG_ERR_BAD_SIGNATURE : 0;
+ leave:
+ gcry_mpi_release (result);
+ gcry_mpi_release (pk.n);
+ gcry_mpi_release (pk.e);
+ gcry_mpi_release (data);
+ gcry_mpi_release (sig);
+ gcry_sexp_release (l1);
+ _gcry_pk_util_free_encoding_ctx (&ctx);
+ if (DBG_CIPHER)
+ log_debug ("rsa_verify => %s\n", rc?gpg_strerror (rc):"good");
return rc;
}
@@ -1423,14 +1464,6 @@ run_selftests (int algo, int extended, selftest_report_func_t report)
-static const char *rsa_names[] =
- {
- "rsa",
- "openpgp-rsa",
- "oid.1.2.840.113549.1.1.1",
- NULL,
- };
-
gcry_pk_spec_t _gcry_pubkey_spec_rsa =
{
GCRY_PK_RSA, { 0, 1 },
diff --git a/src/cipher-proto.h b/src/cipher-proto.h
index 7a54930c..96d8bf6e 100644
--- a/src/cipher-proto.h
+++ b/src/cipher-proto.h
@@ -84,14 +84,9 @@ typedef gcry_err_code_t (*gcry_pk_sign_t) (int algo,
int hashalgo);
/* Type for the pk_verify function. */
-typedef gcry_err_code_t (*gcry_pk_verify_t) (int algo,
- gcry_mpi_t hash,
- gcry_mpi_t *data,
- gcry_mpi_t *pkey,
- int (*cmp) (void *, gcry_mpi_t),
- void *opaquev,
- int flags,
- int hashalgo);
+typedef gcry_err_code_t (*gcry_pk_verify_t) (gcry_sexp_t s_sig,
+ gcry_sexp_t s_data,
+ gcry_sexp_t s_key);
/* Type for the pk_get_nbits function. */
typedef unsigned (*gcry_pk_get_nbits_t) (gcry_sexp_t keyparms);
diff --git a/src/g10lib.h b/src/g10lib.h
index 43281ad3..0ada30a4 100644
--- a/src/g10lib.h
+++ b/src/g10lib.h
@@ -66,7 +66,6 @@
#define GCC_ATTR_FORMAT_ARG(a)
#endif
-
/* I am not sure since when the unused attribute is really supported.
In any case it it only needed for gcc versions which print a
warning. Thus let us require gcc >= 3.5. */
@@ -76,6 +75,12 @@
#define GCC_ATTR_UNUSED
#endif
+#if __GNUC__ >= 4
+# define GCC_ATTR_SENTINEL(a) __attribute__ ((sentinel(a)))
+#else
+# define GCC_ATTR_SENTINEL(a)
+#endif
+
/* Gettext macros. */
diff --git a/tests/basic.c b/tests/basic.c
index e9709d5c..13a8600b 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -3368,7 +3368,8 @@ check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo)
continue;
if (verbose)
- fprintf (stderr, " test %d, signature test %d\n", n, dataidx);
+ fprintf (stderr, " test %d, signature test %d (%s)\n",
+ n, dataidx, gcry_pk_algo_name (algo));
rc = gcry_sexp_sscan (&hash, NULL, datas[dataidx].data,
strlen (datas[dataidx].data));
@@ -4066,6 +4067,7 @@ main (int argc, char **argv)
int debug = 0;
int use_fips = 0;
int selftest_only = 0;
+ int pubkey_only = 0;
if (argc)
{ argc--; argv++; }
@@ -4099,6 +4101,12 @@ main (int argc, char **argv)
verbose += 2;
argc--; argv++;
}
+ else if (!strcmp (*argv, "--pubkey"))
+ {
+ pubkey_only = 1;
+ verbose += 2;
+ argc--; argv++;
+ }
else if (!strcmp (*argv, "--die"))
{
die_on_error = 1;
@@ -4131,7 +4139,9 @@ main (int argc, char **argv)
/* No valuable keys are create, so we can speed up our RNG. */
gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
- if (!selftest_only)
+ if (pubkey_only)
+ check_pubkey ();
+ else if (!selftest_only)
{
check_ciphers ();
check_cipher_modes ();