| /* pubkey.c - pubkey dispatcher |
| * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005, |
| * 2007, 2008, 2011 Free Software Foundation, Inc. |
| * Copyright (C) 2013 g10 Code GmbH |
| * |
| * This file is part of Libgcrypt. |
| * |
| * Libgcrypt is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU Lesser general Public License as |
| * published by the Free Software Foundation; either version 2.1 of |
| * the License, or (at your option) any later version. |
| * |
| * Libgcrypt is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this program; if not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include <config.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| |
| #include "g10lib.h" |
| #include "mpi.h" |
| #include "cipher.h" |
| #include "ath.h" |
| #include "context.h" |
| #include "pubkey-internal.h" |
| |
| |
| /* This is the list of the public-key algorithms included in |
| Libgcrypt. */ |
| static gcry_pk_spec_t *pubkey_list[] = |
| { |
| #if USE_ECC |
| &_gcry_pubkey_spec_ecc, |
| #endif |
| #if USE_RSA |
| &_gcry_pubkey_spec_rsa, |
| #endif |
| #if USE_DSA |
| &_gcry_pubkey_spec_dsa, |
| #endif |
| #if USE_ELGAMAL |
| &_gcry_pubkey_spec_elg, |
| #endif |
| NULL |
| }; |
| |
| |
| static int |
| map_algo (int algo) |
| { |
| switch (algo) |
| { |
| case GCRY_PK_ECDSA: |
| case GCRY_PK_ECDH: |
| return GCRY_PK_ECC; |
| case GCRY_PK_ELG_E: |
| return GCRY_PK_ELG; |
| default: |
| return algo; |
| } |
| } |
| |
| |
| |
| /* Return the spec structure for the public key algorithm ALGO. For |
| an unknown algorithm NULL is returned. */ |
| static gcry_pk_spec_t * |
| spec_from_algo (int algo) |
| { |
| int idx; |
| gcry_pk_spec_t *spec; |
| |
| algo = map_algo (algo); |
| |
| for (idx = 0; (spec = pubkey_list[idx]); idx++) |
| if (algo == spec->algo) |
| return spec; |
| return NULL; |
| } |
| |
| |
| /* Return the spec structure for the public key algorithm with NAME. |
| For an unknown name NULL is returned. */ |
| static gcry_pk_spec_t * |
| spec_from_name (const char *name) |
| { |
| gcry_pk_spec_t *spec; |
| int idx; |
| const char **aliases; |
| |
| for (idx=0; (spec = pubkey_list[idx]); idx++) |
| { |
| if (!stricmp (name, spec->name)) |
| return spec; |
| for (aliases = spec->aliases; *aliases; aliases++) |
| if (!stricmp (name, *aliases)) |
| return spec; |
| } |
| |
| return NULL; |
| } |
| |
| |
| |
| /* Given the s-expression SEXP with the first element be either |
| * "private-key" or "public-key" return the spec structure for it. We |
| * look through the list to find a list beginning with "private-key" |
| * or "public-key" - the first one found is used. If WANT_PRIVATE is |
| * set the function will only succeed if a private key has been given. |
| * On success the spec is stored at R_SPEC. On error NULL is stored |
| * at R_SPEC and an error code returned. If R_PARMS is not NULL and |
| * the fucntion returns success, the parameter list below |
| * "private-key" or "public-key" is stored there and the caller must |
| * call gcry_sexp_release on it. |
| */ |
| static gcry_err_code_t |
| spec_from_sexp (gcry_sexp_t sexp, int want_private, |
| gcry_pk_spec_t **r_spec, gcry_sexp_t *r_parms) |
| { |
| gcry_sexp_t list, l2; |
| char *name; |
| 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 |
| the private key anyway. The rationale for this is that the |
| private key is a superset of the public key. */ |
| list = sexp_find_token (sexp, want_private? "private-key":"public-key", 0); |
| if (!list && !want_private) |
| list = sexp_find_token (sexp, "private-key", 0); |
| if (!list) |
| return GPG_ERR_INV_OBJ; /* Does not contain a key object. */ |
| |
| l2 = sexp_cadr (list); |
| sexp_release (list); |
| list = l2; |
| name = sexp_nth_string (list, 0); |
| if (!name) |
| { |
| sexp_release ( list ); |
| return GPG_ERR_INV_OBJ; /* Invalid structure of object. */ |
| } |
| spec = spec_from_name (name); |
| xfree (name); |
| if (!spec) |
| { |
| sexp_release (list); |
| return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ |
| } |
| *r_spec = spec; |
| if (r_parms) |
| *r_parms = list; |
| else |
| sexp_release (list); |
| return 0; |
| } |
| |
| |
| |
| /* Disable the use of the algorithm ALGO. This is not thread safe and |
| should thus be called early. */ |
| static void |
| disable_pubkey_algo (int algo) |
| { |
| gcry_pk_spec_t *spec = spec_from_algo (algo); |
| |
| if (spec) |
| spec->flags.disabled = 1; |
| } |
| |
| |
| |
| /* |
| * Map a string to the pubkey algo |
| */ |
| int |
| _gcry_pk_map_name (const char *string) |
| { |
| gcry_pk_spec_t *spec; |
| |
| if (!string) |
| return 0; |
| spec = spec_from_name (string); |
| if (!spec) |
| return 0; |
| if (spec->flags.disabled) |
| return 0; |
| return spec->algo; |
| } |
| |
| |
| /* Map the public key algorithm whose ID is contained in ALGORITHM to |
| a string representation of the algorithm name. For unknown |
| algorithm IDs this functions returns "?". */ |
| const char * |
| _gcry_pk_algo_name (int algo) |
| { |
| gcry_pk_spec_t *spec; |
| |
| spec = spec_from_algo (algo); |
| if (spec) |
| return spec->name; |
| return "?"; |
| } |
| |
| |
| /**************** |
| * A USE of 0 means: don't care. |
| */ |
| static gcry_err_code_t |
| check_pubkey_algo (int algo, unsigned use) |
| { |
| gcry_err_code_t err = 0; |
| gcry_pk_spec_t *spec; |
| |
| spec = spec_from_algo (algo); |
| if (spec) |
| { |
| if (((use & GCRY_PK_USAGE_SIGN) |
| && (! (spec->use & GCRY_PK_USAGE_SIGN))) |
| || ((use & GCRY_PK_USAGE_ENCR) |
| && (! (spec->use & GCRY_PK_USAGE_ENCR)))) |
| err = GPG_ERR_WRONG_PUBKEY_ALGO; |
| } |
| else |
| err = GPG_ERR_PUBKEY_ALGO; |
| |
| return err; |
| } |
| |
| |
| /**************** |
| * Return the number of public key material numbers |
| */ |
| static int |
| pubkey_get_npkey (int algo) |
| { |
| gcry_pk_spec_t *spec = spec_from_algo (algo); |
| |
| return spec? strlen (spec->elements_pkey) : 0; |
| } |
| |
| |
| /**************** |
| * Return the number of secret key material numbers |
| */ |
| static int |
| pubkey_get_nskey (int algo) |
| { |
| gcry_pk_spec_t *spec = spec_from_algo (algo); |
| |
| return spec? strlen (spec->elements_skey) : 0; |
| } |
| |
| |
| /**************** |
| * Return the number of signature material numbers |
| */ |
| static int |
| pubkey_get_nsig (int algo) |
| { |
| gcry_pk_spec_t *spec = spec_from_algo (algo); |
| |
| return spec? strlen (spec->elements_sig) : 0; |
| } |
| |
| /**************** |
| * Return the number of encryption material numbers |
| */ |
| static int |
| pubkey_get_nenc (int algo) |
| { |
| gcry_pk_spec_t *spec = spec_from_algo (algo); |
| |
| return spec? strlen (spec->elements_enc) : 0; |
| } |
| |
| |
| |
| /* |
| Do a PK encrypt operation |
| |
| Caller has to provide a public key as the SEXP pkey and data as a |
| SEXP with just one MPI in it. Alternatively S_DATA might be a |
| complex S-Expression, similar to the one used for signature |
| verification. This provides a flag which allows to handle PKCS#1 |
| block type 2 padding. The function returns a sexp which may be |
| passed to to pk_decrypt. |
| |
| Returns: 0 or an errorcode. |
| |
| 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> |
| (<param_name1> <mpi>) |
| ... |
| (<param_namen> <mpi>) |
| )) |
| |
| */ |
| gcry_err_code_t |
| _gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey) |
| { |
| gcry_err_code_t rc; |
| gcry_pk_spec_t *spec; |
| gcry_sexp_t keyparms; |
| |
| *r_ciph = NULL; |
| |
| rc = spec_from_sexp (s_pkey, 0, &spec, &keyparms); |
| if (rc) |
| goto leave; |
| |
| if (spec->encrypt) |
| rc = spec->encrypt (r_ciph, s_data, keyparms); |
| else |
| rc = GPG_ERR_NOT_IMPLEMENTED; |
| |
| leave: |
| sexp_release (keyparms); |
| return rc; |
| } |
| |
| |
| /* |
| Do a PK decrypt operation |
| |
| Caller has to provide a secret key as the SEXP skey and data in a |
| format as created by gcry_pk_encrypt. For historic reasons the |
| function returns simply an MPI as an S-expression part; this is |
| deprecated and the new method should be used which returns a real |
| S-expressionl this is selected by adding at least an empty flags |
| list to S_DATA. |
| |
| Returns: 0 or an errorcode. |
| |
| s_data = (enc-val |
| [(flags [raw, pkcs1, oaep])] |
| (<algo> |
| (<param_name1> <mpi>) |
| ... |
| (<param_namen> <mpi>) |
| )) |
| s_skey = <key-as-defined-in-sexp_to_key> |
| r_plain= Either an incomplete S-expression without the parentheses |
| or if the flags list is used (even if empty) a real S-expression: |
| (value PLAIN). In raw mode (or no flags given) the returned value |
| is to be interpreted as a signed MPI, thus it may have an extra |
| leading zero octet even if not included in the original data. |
| With pkcs1 or oaep decoding enabled the returned value is a |
| verbatim octet string. |
| */ |
| gcry_err_code_t |
| _gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey) |
| { |
| gcry_err_code_t rc; |
| gcry_pk_spec_t *spec; |
| gcry_sexp_t keyparms; |
| |
| *r_plain = NULL; |
| |
| rc = spec_from_sexp (s_skey, 1, &spec, &keyparms); |
| if (rc) |
| goto leave; |
| |
| if (spec->decrypt) |
| rc = spec->decrypt (r_plain, s_data, keyparms); |
| else |
| rc = GPG_ERR_NOT_IMPLEMENTED; |
| |
| leave: |
| sexp_release (keyparms); |
| return rc; |
| } |
| |
| |
| |
| /* |
| Create a signature. |
| |
| Caller has to provide a secret key as the SEXP skey and data |
| expressed as a SEXP list hash with only one element which should |
| instantly be available as a MPI. Alternatively the structure given |
| below may be used for S_HASH, it provides the abiliy to pass flags |
| to the operation; the flags defined by now are "pkcs1" which does |
| PKCS#1 block type 1 style padding and "pss" for PSS encoding. |
| |
| Returns: 0 or an errorcode. |
| In case of 0 the function returns a new SEXP with the |
| signature value; the structure of this signature depends on the |
| other arguments but is always suitable to be passed to |
| gcry_pk_verify |
| |
| s_hash = See comment for _gcry-pk_util_data_to_mpi |
| |
| s_skey = <key-as-defined-in-sexp_to_key> |
| r_sig = (sig-val |
| (<algo> |
| (<param_name1> <mpi>) |
| ... |
| (<param_namen> <mpi>)) |
| [(hash algo)]) |
| |
| Note that (hash algo) in R_SIG is not used. |
| */ |
| gcry_err_code_t |
| _gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey) |
| { |
| gcry_err_code_t rc; |
| gcry_pk_spec_t *spec; |
| gcry_sexp_t keyparms; |
| |
| *r_sig = NULL; |
| |
| rc = spec_from_sexp (s_skey, 1, &spec, &keyparms); |
| if (rc) |
| goto leave; |
| |
| if (spec->sign) |
| rc = spec->sign (r_sig, s_hash, keyparms); |
| else |
| rc = GPG_ERR_NOT_IMPLEMENTED; |
| |
| leave: |
| sexp_release (keyparms); |
| return rc; |
| } |
| |
| |
| /* |
| Verify a signature. |
| |
| Caller has to supply the public key pkey, the signature sig and his |
| hashvalue data. Public key has to be a standard public key given |
| as an S-Exp, sig is a S-Exp as returned from gcry_pk_sign and data |
| must be an S-Exp like the one in sign too. */ |
| gcry_err_code_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; |
| gcry_sexp_t keyparms; |
| |
| rc = spec_from_sexp (s_pkey, 0, &spec, &keyparms); |
| if (rc) |
| goto leave; |
| |
| if (spec->verify) |
| rc = spec->verify (s_sig, s_hash, keyparms); |
| else |
| rc = GPG_ERR_NOT_IMPLEMENTED; |
| |
| leave: |
| sexp_release (keyparms); |
| return rc; |
| } |
| |
| |
| /* |
| Test a key. |
| |
| This may be used either for a public or a secret key to see whether |
| the internal structure is okay. |
| |
| Returns: 0 or an errorcode. |
| |
| NOTE: We currently support only secret key checking. */ |
| gcry_err_code_t |
| _gcry_pk_testkey (gcry_sexp_t s_key) |
| { |
| gcry_err_code_t rc; |
| gcry_pk_spec_t *spec; |
| gcry_sexp_t keyparms; |
| |
| 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: |
| sexp_release (keyparms); |
| return rc; |
| } |
| |
| |
| /* |
| Create a public key pair and return it in r_key. |
| How the key is created depends on s_parms: |
| (genkey |
| (algo |
| (parameter_name_1 ....) |
| .... |
| (parameter_name_n ....) |
| )) |
| The key is returned in a format depending on the |
| algorithm. Both, private and secret keys are returned |
| and optionally some additional informatin. |
| For elgamal we return this structure: |
| (key-data |
| (public-key |
| (elg |
| (p <mpi>) |
| (g <mpi>) |
| (y <mpi>) |
| ) |
| ) |
| (private-key |
| (elg |
| (p <mpi>) |
| (g <mpi>) |
| (y <mpi>) |
| (x <mpi>) |
| ) |
| ) |
| (misc-key-info |
| (pm1-factors n1 n2 ... nn) |
| )) |
| */ |
| gcry_err_code_t |
| _gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms) |
| { |
| gcry_pk_spec_t *spec = NULL; |
| gcry_sexp_t list = NULL; |
| gcry_sexp_t l2 = NULL; |
| char *name = NULL; |
| gcry_err_code_t rc; |
| |
| *r_key = NULL; |
| |
| list = sexp_find_token (s_parms, "genkey", 0); |
| if (!list) |
| { |
| rc = GPG_ERR_INV_OBJ; /* Does not contain genkey data. */ |
| goto leave; |
| } |
| |
| l2 = sexp_cadr (list); |
| sexp_release (list); |
| list = l2; |
| l2 = NULL; |
| if (! list) |
| { |
| rc = GPG_ERR_NO_OBJ; /* No cdr for the genkey. */ |
| goto leave; |
| } |
| |
| name = _gcry_sexp_nth_string (list, 0); |
| if (!name) |
| { |
| rc = GPG_ERR_INV_OBJ; /* Algo string missing. */ |
| goto leave; |
| } |
| |
| spec = spec_from_name (name); |
| xfree (name); |
| name = NULL; |
| if (!spec) |
| { |
| rc = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ |
| goto leave; |
| } |
| |
| if (spec->generate) |
| rc = spec->generate (list, r_key); |
| else |
| rc = GPG_ERR_NOT_IMPLEMENTED; |
| |
| leave: |
| sexp_release (list); |
| xfree (name); |
| sexp_release (l2); |
| |
| return rc; |
| } |
| |
| |
| /* |
| Get the number of nbits from the public key. |
| |
| Hmmm: Should we have really this function or is it better to have a |
| more general function to retrieve different properties of the key? */ |
| unsigned int |
| _gcry_pk_get_nbits (gcry_sexp_t key) |
| { |
| gcry_pk_spec_t *spec; |
| gcry_sexp_t parms; |
| unsigned int nbits; |
| |
| /* Parsing KEY might be considered too much overhead. For example |
| for RSA we would only need to look at P and stop parsing right |
| away. However, with ECC things are more complicate in that only |
| a curve name might be specified. Thus we need to tear the sexp |
| apart. */ |
| |
| if (spec_from_sexp (key, 0, &spec, &parms)) |
| return 0; /* Error - 0 is a suitable indication for that. */ |
| |
| nbits = spec->get_nbits (parms); |
| sexp_release (parms); |
| return nbits; |
| } |
| |
| |
| /* Return the so called KEYGRIP which is the SHA-1 hash of the public |
| key parameters expressed in a way depending on the algorithm. |
| |
| ARRAY must either be 20 bytes long or NULL; in the latter case a |
| newly allocated array of that size is returned, otherwise ARRAY or |
| NULL is returned to indicate an error which is most likely an |
| unknown algorithm. The function accepts public or secret keys. */ |
| unsigned char * |
| _gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array) |
| { |
| gcry_sexp_t list = NULL; |
| gcry_sexp_t l2 = NULL; |
| gcry_pk_spec_t *spec = NULL; |
| const char *s; |
| char *name = NULL; |
| int idx; |
| const char *elems; |
| gcry_md_hd_t md = NULL; |
| int okay = 0; |
| |
| /* Check that the first element is valid. */ |
| list = sexp_find_token (key, "public-key", 0); |
| if (! list) |
| list = sexp_find_token (key, "private-key", 0); |
| if (! list) |
| list = sexp_find_token (key, "protected-private-key", 0); |
| if (! list) |
| list = sexp_find_token (key, "shadowed-private-key", 0); |
| if (! list) |
| return NULL; /* No public- or private-key object. */ |
| |
| l2 = sexp_cadr (list); |
| sexp_release (list); |
| list = l2; |
| l2 = NULL; |
| |
| name = _gcry_sexp_nth_string (list, 0); |
| if (!name) |
| goto fail; /* Invalid structure of object. */ |
| |
| spec = spec_from_name (name); |
| if (!spec) |
| goto fail; /* Unknown algorithm. */ |
| |
| elems = spec->elements_grip; |
| if (!elems) |
| goto fail; /* No grip parameter. */ |
| |
| if (_gcry_md_open (&md, GCRY_MD_SHA1, 0)) |
| goto fail; |
| |
| if (spec->comp_keygrip) |
| { |
| /* Module specific method to compute a keygrip. */ |
| if (spec->comp_keygrip (md, list)) |
| goto fail; |
| } |
| else |
| { |
| /* Generic method to compute a keygrip. */ |
| for (idx = 0, s = elems; *s; s++, idx++) |
| { |
| const char *data; |
| size_t datalen; |
| char buf[30]; |
| |
| l2 = sexp_find_token (list, s, 1); |
| if (! l2) |
| goto fail; |
| data = sexp_nth_data (l2, 1, &datalen); |
| if (! data) |
| goto fail; |
| |
| snprintf (buf, sizeof buf, "(1:%c%u:", *s, (unsigned int)datalen); |
| _gcry_md_write (md, buf, strlen (buf)); |
| _gcry_md_write (md, data, datalen); |
| sexp_release (l2); |
| l2 = NULL; |
| _gcry_md_write (md, ")", 1); |
| } |
| } |
| |
| if (!array) |
| { |
| array = xtrymalloc (20); |
| if (! array) |
| goto fail; |
| } |
| |
| memcpy (array, _gcry_md_read (md, GCRY_MD_SHA1), 20); |
| okay = 1; |
| |
| fail: |
| xfree (name); |
| sexp_release (l2); |
| _gcry_md_close (md); |
| sexp_release (list); |
| return okay? array : NULL; |
| } |
| |
| |
| |
| const char * |
| _gcry_pk_get_curve (gcry_sexp_t key, int iterator, unsigned int *r_nbits) |
| { |
| const char *result = NULL; |
| gcry_pk_spec_t *spec; |
| gcry_sexp_t keyparms = NULL; |
| |
| if (r_nbits) |
| *r_nbits = 0; |
| |
| if (key) |
| { |
| iterator = 0; |
| |
| if (spec_from_sexp (key, 0, &spec, &keyparms)) |
| return NULL; |
| } |
| else |
| { |
| spec = spec_from_name ("ecc"); |
| if (!spec) |
| return NULL; |
| } |
| |
| if (spec->get_curve) |
| result = spec->get_curve (keyparms, iterator, r_nbits); |
| |
| sexp_release (keyparms); |
| return result; |
| } |
| |
| |
| |
| gcry_sexp_t |
| _gcry_pk_get_param (int algo, const char *name) |
| { |
| gcry_sexp_t result = NULL; |
| gcry_pk_spec_t *spec = NULL; |
| |
| algo = map_algo (algo); |
| |
| if (algo != GCRY_PK_ECC) |
| return NULL; |
| |
| spec = spec_from_name ("ecc"); |
| if (spec) |
| { |
| if (spec && spec->get_curve_param) |
| result = spec->get_curve_param (name); |
| } |
| return result; |
| } |
| |
| |
| |
| gcry_err_code_t |
| _gcry_pk_ctl (int cmd, void *buffer, size_t buflen) |
| { |
| gcry_err_code_t rc = 0; |
| |
| switch (cmd) |
| { |
| case GCRYCTL_DISABLE_ALGO: |
| /* This one expects a buffer pointing to an integer with the |
| algo number. */ |
| if ((! buffer) || (buflen != sizeof (int))) |
| rc = GPG_ERR_INV_ARG; |
| else |
| disable_pubkey_algo (*((int *) buffer)); |
| break; |
| |
| default: |
| rc = GPG_ERR_INV_OP; |
| } |
| |
| return rc; |
| } |
| |
| |
| /* Return information about the given algorithm |
| |
| WHAT selects the kind of information returned: |
| |
| GCRYCTL_TEST_ALGO: |
| Returns 0 when the specified algorithm is available for use. |
| Buffer must be NULL, nbytes may have the address of a variable |
| with the required usage of the algorithm. It may be 0 for don't |
| care or a combination of the GCRY_PK_USAGE_xxx flags; |
| |
| GCRYCTL_GET_ALGO_USAGE: |
| Return the usage flags for the given algo. An invalid algo |
| returns 0. Disabled algos are ignored here because we |
| only want to know whether the algo is at all capable of |
| the usage. |
| |
| Note: Because this function is in most cases used to return an |
| integer value, we can make it easier for the caller to just look at |
| the return value. The caller will in all cases consult the value |
| and thereby detecting whether a error occurred or not (i.e. while |
| checking the block size) */ |
| gcry_err_code_t |
| _gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes) |
| { |
| gcry_err_code_t rc = 0; |
| |
| switch (what) |
| { |
| case GCRYCTL_TEST_ALGO: |
| { |
| int use = nbytes ? *nbytes : 0; |
| if (buffer) |
| rc = GPG_ERR_INV_ARG; |
| else if (check_pubkey_algo (algorithm, use)) |
| rc = GPG_ERR_PUBKEY_ALGO; |
| break; |
| } |
| |
| case GCRYCTL_GET_ALGO_USAGE: |
| { |
| gcry_pk_spec_t *spec; |
| |
| spec = spec_from_algo (algorithm); |
| *nbytes = spec? spec->use : 0; |
| break; |
| } |
| |
| case GCRYCTL_GET_ALGO_NPKEY: |
| { |
| /* FIXME? */ |
| int npkey = pubkey_get_npkey (algorithm); |
| *nbytes = npkey; |
| break; |
| } |
| case GCRYCTL_GET_ALGO_NSKEY: |
| { |
| /* FIXME? */ |
| int nskey = pubkey_get_nskey (algorithm); |
| *nbytes = nskey; |
| break; |
| } |
| case GCRYCTL_GET_ALGO_NSIGN: |
| { |
| /* FIXME? */ |
| int nsign = pubkey_get_nsig (algorithm); |
| *nbytes = nsign; |
| break; |
| } |
| case GCRYCTL_GET_ALGO_NENCR: |
| { |
| /* FIXME? */ |
| int nencr = pubkey_get_nenc (algorithm); |
| *nbytes = nencr; |
| break; |
| } |
| |
| default: |
| rc = GPG_ERR_INV_OP; |
| } |
| |
| return rc; |
| } |
| |
| |
| /* Return an S-expression representing the context CTX. Depending on |
| the state of that context, the S-expression may either be a public |
| key, a private key or any other object used with public key |
| operations. On success a new S-expression is stored at R_SEXP and |
| 0 is returned, on error NULL is store there and an error code is |
| returned. MODE is either 0 or one of the GCRY_PK_GET_xxx values. |
| |
| As of now it only support certain ECC operations because a context |
| object is right now only defined for ECC. Over time this function |
| will be extended to cover more algorithms. Note also that the name |
| of the function is gcry_pubkey_xxx and not gcry_pk_xxx. The idea |
| is that we will eventually provide variants of the existing |
| gcry_pk_xxx functions which will take a context parameter. */ |
| gcry_err_code_t |
| _gcry_pubkey_get_sexp (gcry_sexp_t *r_sexp, int mode, gcry_ctx_t ctx) |
| { |
| mpi_ec_t ec; |
| |
| if (!r_sexp) |
| return GPG_ERR_INV_VALUE; |
| *r_sexp = NULL; |
| switch (mode) |
| { |
| case 0: |
| case GCRY_PK_GET_PUBKEY: |
| case GCRY_PK_GET_SECKEY: |
| break; |
| default: |
| return GPG_ERR_INV_VALUE; |
| } |
| if (!ctx) |
| return GPG_ERR_NO_CRYPT_CTX; |
| |
| ec = _gcry_ctx_find_pointer (ctx, CONTEXT_TYPE_EC); |
| if (ec) |
| return _gcry_pk_ecc_get_sexp (r_sexp, mode, ec); |
| |
| return GPG_ERR_WRONG_CRYPT_CTX; |
| } |
| |
| |
| |
| /* Explicitly initialize this module. */ |
| gcry_err_code_t |
| _gcry_pk_init (void) |
| { |
| return 0; |
| } |
| |
| |
| /* Run the selftests for pubkey algorithm ALGO with optional reporting |
| function REPORT. */ |
| gpg_error_t |
| _gcry_pk_selftest (int algo, int extended, selftest_report_func_t report) |
| { |
| gcry_err_code_t ec; |
| gcry_pk_spec_t *spec; |
| |
| algo = map_algo (algo); |
| spec = spec_from_algo (algo); |
| if (spec && !spec->flags.disabled && spec->selftest) |
| ec = spec->selftest (algo, extended, report); |
| else |
| { |
| ec = GPG_ERR_PUBKEY_ALGO; |
| /* Fixme: We need to change the report fucntion to allow passing |
| of an encryption mode (e.g. pkcs1, ecdsa, or ecdh). */ |
| if (report) |
| report ("pubkey", algo, "module", |
| spec && !spec->flags.disabled? |
| "no selftest available" : |
| spec? "algorithm disabled" : |
| "algorithm not found"); |
| } |
| |
| return gpg_error (ec); |
| } |