summaryrefslogtreecommitdiff
path: root/cipher/pubkey.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2013-10-11 22:37:41 +0200
committerWerner Koch <wk@gnupg.org>2013-10-11 22:37:58 +0200
commita951c061523e1c13f1358c9760fc3a9d787ab2d4 (patch)
tree5ea15233dbeffa041c129920c6ab5fa93b40b75e /cipher/pubkey.c
parent07950c865a901afc48acb46f0695040cadfd5068 (diff)
downloadlibgcrypt-a951c061523e1c13f1358c9760fc3a9d787ab2d4.tar.gz
pubkey: Move sexp parsing of remaining fucntions to the modules.
* cipher/pubkey.c (release_mpi_array): Remove. (pubkey_check_secret_key): Remove. (sexp_elements_extract): Remove. (sexp_elements_extract_ecc): Remove. (sexp_to_key): Remove. (get_hash_algo): Remove. (gcry_pk_testkey): Revamp. (gcry_pk_get_curve): Revamp. * cipher/rsa.c (rsa_check_secret_key): Revamp. * cipher/elgamal.c (elg_check_secret_key): Revamp. * cipher/dsa.c (dsa_check_secret_key): Revamp. * cipher/ecc.c (ecc_check_secret_key): Revamp. * cipher/ecc-curves.c: Include cipher.h and pubkey-internal.h (_gcry_ecc_get_curve): Revamp. * cipher/pubkey-util.c (_gcry_pk_util_extract_mpis): Set passed and used parameters on error to NULL. -- That is the final part of the changes modulo introduced regressions. pubkey.c is now actually maintainable code. Signed-off-by: Werner Koch <wk@gnupg.org>
Diffstat (limited to 'cipher/pubkey.c')
-rw-r--r--cipher/pubkey.c480
1 files changed, 23 insertions, 457 deletions
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index d7a474d8..c1d8bbc6 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -183,20 +183,6 @@ disable_pubkey_algo (int algo)
-/* Free the MPIs stored in the NULL terminated ARRAY of MPIs and set
- the slots to NULL. */
-static void
-release_mpi_array (gcry_mpi_t *array)
-{
- for (; *array; array++)
- {
- mpi_free(*array);
- *array = NULL;
- }
-}
-
-
-
/*
* Map a string to the pubkey algo
*/
@@ -303,396 +289,7 @@ pubkey_get_nenc (int algo)
}
-static gcry_err_code_t
-pubkey_check_secret_key (int algo, gcry_mpi_t *skey)
-{
- gcry_err_code_t rc;
- gcry_pk_spec_t *spec = spec_from_algo (algo);
-
- if (spec && spec->check_secret_key)
- rc = spec->check_secret_key (algo, skey);
- else if (spec)
- rc = GPG_ERR_NOT_IMPLEMENTED;
- else
- rc = GPG_ERR_PUBKEY_ALGO;
-
- return rc;
-}
-
-
-/* Internal function. */
-static gcry_err_code_t
-sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names,
- gcry_mpi_t *elements, const char *algo_name, int opaque)
-{
- gcry_err_code_t err = 0;
- int i, idx;
- const char *name;
- gcry_sexp_t list;
-
- for (name = element_names, idx = 0; *name && !err; name++, idx++)
- {
- list = gcry_sexp_find_token (key_sexp, name, 1);
- if (!list)
- elements[idx] = NULL;
- else if (opaque)
- {
- elements[idx] = _gcry_sexp_nth_opaque_mpi (list, 1);
- gcry_sexp_release (list);
- if (!elements[idx])
- err = GPG_ERR_INV_OBJ;
- }
- else
- {
- elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
- gcry_sexp_release (list);
- if (!elements[idx])
- err = GPG_ERR_INV_OBJ;
- }
- }
-
- if (!err)
- {
- /* Check that all elements are available. */
- for (name = element_names, i = 0; *name; name++, i++)
- if (!elements[i])
- break;
- if (*name)
- {
- err = GPG_ERR_NO_OBJ;
- /* Some are missing. Before bailing out we test for
- optional parameters. */
- if (algo_name && !strcmp (algo_name, "RSA")
- && !strcmp (element_names, "nedpqu") )
- {
- /* This is RSA. Test whether we got N, E and D and that
- the optional P, Q and U are all missing. */
- if (elements[0] && elements[1] && elements[2]
- && !elements[3] && !elements[4] && !elements[5])
- err = 0;
- }
- }
- }
-
-
- if (err)
- {
- for (i = 0; i < idx; i++)
- if (elements[i])
- mpi_free (elements[i]);
- }
- return err;
-}
-
-
-/* Internal function used for ecc. Note, that this function makes use
- of its intimate knowledge about the ECC parameters from ecc.c. */
-static gcry_err_code_t
-sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names,
- gcry_mpi_t *elements, gcry_pk_spec_t *spec,
- int want_private)
-
-{
- gcry_err_code_t err = 0;
- int idx;
- const char *name;
- gcry_sexp_t list;
-
- /* Clear the array for easier error cleanup. */
- for (name = element_names, idx = 0; *name; name++, idx++)
- elements[idx] = NULL;
- gcry_assert (idx >= 5); /* We know that ECC has at least 5 elements
- (params only) or 6 (full public key). */
- if (idx == 5)
- elements[5] = NULL; /* Extra clear for the params only case. */
-
-
- /* Init the array with the available curve parameters. */
- for (name = element_names, idx = 0; *name && !err; name++, idx++)
- {
- list = gcry_sexp_find_token (key_sexp, name, 1);
- if (!list)
- elements[idx] = NULL;
- else
- {
- switch (idx)
- {
- case 5: /* The public and */
- case 6: /* the secret key must to be passed opaque. */
- elements[idx] = _gcry_sexp_nth_opaque_mpi (list, 1);
- break;
- default:
- elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_STD);
- break;
- }
- gcry_sexp_release (list);
- if (!elements[idx])
- {
- err = GPG_ERR_INV_OBJ;
- goto leave;
- }
- }
- }
-
- /* Check whether a curve parameter has been given and then fill any
- missing elements. */
- list = gcry_sexp_find_token (key_sexp, "curve", 5);
- if (list)
- {
- if (spec->get_param)
- {
- char *curve;
- gcry_mpi_t params[6];
-
- for (idx = 0; idx < DIM(params); idx++)
- params[idx] = NULL;
-
- curve = _gcry_sexp_nth_string (list, 1);
- gcry_sexp_release (list);
- if (!curve)
- {
- /* No curve name given (or out of core). */
- err = GPG_ERR_INV_OBJ;
- goto leave;
- }
- err = spec->get_param (curve, params);
- gcry_free (curve);
- if (err)
- goto leave;
-
- for (idx = 0; idx < DIM(params); idx++)
- {
- if (!elements[idx])
- elements[idx] = params[idx];
- else
- mpi_free (params[idx]);
- }
- }
- else
- {
- gcry_sexp_release (list);
- err = GPG_ERR_INV_OBJ; /* "curve" given but ECC not supported. */
- goto leave;
- }
- }
-
- /* Check that all parameters are known. */
- for (name = element_names, idx = 0; *name; name++, idx++)
- if (!elements[idx])
- {
- if (want_private && *name == 'q')
- ; /* Q is optional. */
- else
- {
- err = GPG_ERR_NO_OBJ;
- goto leave;
- }
- }
-
- leave:
- if (err)
- {
- for (name = element_names, idx = 0; *name; name++, idx++)
- if (elements[idx])
- mpi_free (elements[idx]);
- }
- return err;
-}
-
-
-
-/****************
- * Convert a S-Exp with either a private or a public key to our
- * internal format. Currently we do only support the following
- * algorithms:
- * dsa
- * rsa
- * openpgp-dsa
- * openpgp-rsa
- * openpgp-elg
- * openpgp-elg-sig
- * ecdsa
- * ecdh
- * Provide a SE with the first element be either "private-key" or
- * or "public-key". It is followed by a list with its first element
- * be one of the above algorithm identifiers and the remaning
- * elements are pairs with parameter-id and value.
- * NOTE: we look through the list to find a list beginning with
- * "private-key" or "public-key" - the first one found is used.
- *
- * If OVERRIDE_ELEMS is not NULL those elems override the parameter
- * specification taken from the module. This ise used by
- * gcry_pk_get_curve.
- *
- * Returns: A pointer to an allocated array of MPIs if the return value is
- * zero; the caller has to release this array.
- *
- * Example of a DSA public key:
- * (private-key
- * (dsa
- * (p <mpi>)
- * (g <mpi>)
- * (y <mpi>)
- * (x <mpi>)
- * )
- * )
- * The <mpi> are expected to be in GCRYMPI_FMT_USG
- */
-static gcry_err_code_t
-sexp_to_key (gcry_sexp_t sexp, int want_private, int use,
- const char *override_elems,
- gcry_mpi_t **retarray, gcry_pk_spec_t **r_spec, int *r_is_ecc)
-{
- 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;
- int is_ecc;
-
- /* 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
- the private key anyway. The rationale for this is that the
- private key is a superset of the public key. */
- list = gcry_sexp_find_token (sexp,
- want_private? "private-key":"public-key", 0);
- if (!list && !want_private)
- list = gcry_sexp_find_token (sexp, "private-key", 0);
- if (!list)
- return GPG_ERR_INV_OBJ; /* Does not contain a key object. */
-
- l2 = gcry_sexp_cadr( list );
- gcry_sexp_release ( list );
- list = l2;
- name = _gcry_sexp_nth_string (list, 0);
- if (!name)
- {
- gcry_sexp_release ( list );
- return GPG_ERR_INV_OBJ; /* Invalid structure of object. */
- }
-
- /* Fixme: We should make sure that an ECC key is always named "ecc"
- and not "ecdsa". "ecdsa" should be used for the signature
- itself. We need a function to test whether an algorithm given
- with a key is compatible with an application of the key (signing,
- encryption). For RSA this is easy, but ECC is the first
- algorithm which has many flavours.
-
- We use an ugly hack here to decide whether to use ecdsa or ecdh.
- */
- if (!strcmp (name, "ecc"))
- is_ecc = 2;
- else if (!strcmp (name, "ecdsa") || !strcmp (name, "ecdh"))
- is_ecc = 1;
- else
- is_ecc = 0;
-
- if (is_ecc == 2 && (use & GCRY_PK_USAGE_SIGN))
- spec = spec_from_name ("ecdsa");
- else if (is_ecc == 2 && (use & GCRY_PK_USAGE_ENCR))
- spec = spec_from_name ("ecdh");
- else
- spec = spec_from_name (name);
-
- gcry_free (name);
-
- if (!spec)
- {
- gcry_sexp_release (list);
- return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
- }
-
- if (override_elems)
- elems = override_elems;
- else if (want_private)
- elems = spec->elements_skey;
- else
- elems = spec->elements_pkey;
- array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
- if (!array)
- err = gpg_err_code_from_syserror ();
- if (!err)
- {
- if (is_ecc)
- err = sexp_elements_extract_ecc (list, elems, array, spec,
- want_private);
- else
- err = sexp_elements_extract (list, elems, array, spec->name, 0);
- }
-
- gcry_sexp_release (list);
-
- if (err)
- {
- gcry_free (array);
- }
- else
- {
- *retarray = array;
- *r_spec = spec;
- if (r_is_ecc)
- *r_is_ecc = is_ecc;
- }
-
- return err;
-}
-
-
-
-/* FIXME: This is a duplicate. */
-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;
-}
-
-
+
/*
Do a PK encrypt operation
@@ -881,22 +478,25 @@ gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey)
Returns: 0 or an errorcode.
- s_key = <key-as-defined-in-sexp_to_key> */
+ NOTE: We currently support only secret key checking. */
gcry_error_t
gcry_pk_testkey (gcry_sexp_t s_key)
{
- gcry_pk_spec_t *spec = NULL;
- gcry_mpi_t *key = NULL;
gcry_err_code_t rc;
+ gcry_pk_spec_t *spec;
+ gcry_sexp_t keyparms;
- /* Note we currently support only secret key checking. */
- rc = sexp_to_key (s_key, 1, 0, NULL, &key, &spec, NULL);
- if (!rc)
- {
- rc = pubkey_check_secret_key (spec->algo, key);
- release_mpi_array (key);
- gcry_free (key);
- }
+ rc = spec_from_sexp (s_key, 1, &spec, &keyparms);
+ if (rc)
+ goto leave;
+
+ if (spec->check_secret_key)
+ rc = spec->check_secret_key (keyparms);
+ else
+ rc = GPG_ERR_NOT_IMPLEMENTED;
+
+ leave:
+ gcry_sexp_release (keyparms);
return gcry_error (rc);
}
@@ -1124,13 +724,9 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
const char *
gcry_pk_get_curve (gcry_sexp_t key, int iterator, unsigned int *r_nbits)
{
- gcry_mpi_t *pkey = NULL;
- gcry_sexp_t list = NULL;
- gcry_sexp_t l2;
- char *name = NULL;
const char *result = NULL;
- int want_private = 1;
- gcry_pk_spec_t *spec = NULL;
+ gcry_pk_spec_t *spec;
+ gcry_sexp_t keyparms = NULL;
if (r_nbits)
*r_nbits = 0;
@@ -1139,50 +735,20 @@ gcry_pk_get_curve (gcry_sexp_t key, int iterator, unsigned int *r_nbits)
{
iterator = 0;
- /* Check that the first element is valid. */
- list = gcry_sexp_find_token (key, "public-key", 0);
- if (list)
- want_private = 0;
- if (!list)
- list = gcry_sexp_find_token (key, "private-key", 0);
- if (!list)
- return NULL; /* No public- or private-key object. */
-
- l2 = gcry_sexp_cadr (list);
- gcry_sexp_release (list);
- list = l2;
- l2 = NULL;
-
- name = _gcry_sexp_nth_string (list, 0);
- if (!name)
- goto leave; /* Invalid structure of object. */
-
- /* Get the key. We pass the names of the parameters for
- override_elems; this allows to call this function without the
- actual public key parameter. */
- if (sexp_to_key (key, want_private, 0, "pabgn", &pkey, &spec, NULL))
- goto leave;
+ if (spec_from_sexp (key, 0, &spec, &keyparms))
+ return NULL;
}
else
{
spec = spec_from_name ("ecc");
if (!spec)
- goto leave;
+ return NULL;
}
- if (!spec || !spec->get_curve)
- goto leave;
-
- result = spec->get_curve (pkey, iterator, r_nbits);
+ if (spec->get_curve)
+ result = spec->get_curve (keyparms, iterator, r_nbits);
- leave:
- if (pkey)
- {
- release_mpi_array (pkey);
- gcry_free (pkey);
- }
- gcry_free (name);
- gcry_sexp_release (list);
+ gcry_sexp_release (keyparms);
return result;
}