Diffstat (limited to 'pwmanager/libcrypt/cipher/ac.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | pwmanager/libcrypt/cipher/ac.c | 1390 |
1 files changed, 1390 insertions, 0 deletions
diff --git a/pwmanager/libcrypt/cipher/ac.c b/pwmanager/libcrypt/cipher/ac.c new file mode 100644 index 0000000..c18f243 --- a/dev/null +++ b/pwmanager/libcrypt/cipher/ac.c @@ -0,0 +1,1390 @@ +/* ac.c - Alternative interface for asymmetric cryptography. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + + 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <stddef.h> + +#include "g10lib.h" +#include "cipher.h" + + + +/* At the moment the ac interface is a wrapper around the pk + interface, but this might change somewhen in the future, depending + on how much people prefer the ac interface. */ + +/* Mapping of flag numbers to the according strings as it is expected + for S-expressions. */ +struct number_string +{ + int number; + const char *string; +} gcry_ac_flags[] = + { + { GCRY_AC_FLAG_NO_BLINDING, "no-blinding" }, + { 0, NULL }, + }; + +/* The positions in this list correspond to the values contained in + the gcry_ac_key_type_t enumeration list. */ +static const char *ac_key_identifiers[] = + { + "private-key", + "public-key", + }; + +/* These specifications are needed for key-pair generation; the caller + is allowed to pass additional, algorithm-specific `specs' to + gcry_ac_key_pair_generate. This list is used for decoding the + provided values according to the selected algorithm. */ +struct gcry_ac_key_generate_spec +{ + int algorithm; /* Algorithm for which this flag is + relevant. */ + const char *name; /* Name of this flag. */ + size_t offset; /* Offset in the cipher-specific spec + structure at which the MPI value + associated with this flag is to be + found. */ +} gcry_ac_key_generate_specs[] = + { + { GCRY_AC_RSA, "rsa-use-e", offsetof (gcry_ac_key_spec_rsa_t, e) }, + { 0 }, + }; + +/* Handle structure. */ +struct gcry_ac_handle +{ + int algorithm; /* Algorithm ID associated with this + handle. */ + const char *algorithm_name; /* Name of the algorithm. */ + unsigned int flags; /* Flags, not used yet. */ + gcry_module_t module; /* Reference to the algorithm + module. */ +}; + +/* A named MPI value. */ +typedef struct gcry_ac_mpi +{ + const char *name; /* Name of MPI value. */ + gcry_mpi_t mpi; /* MPI value. */ + unsigned int flags; /* Flags. */ +} gcry_ac_mpi_t; + +/* A data set, that is simply a list of named MPI values. */ +struct gcry_ac_data +{ + gcry_ac_mpi_t *data; /* List of named values. */ + unsigned int data_n; /* Number of values in DATA. */ +}; + +/* The key in `native' ac form and as an S-expression. */ +struct gcry_ac_key +{ + gcry_ac_data_t data; /* Data in native ac structure. */ + gcry_sexp_t data_sexp; /* Data as an S-expression. */ + gcry_ac_key_type_t type; /* Type of the key. */ +}; + +/* Two keys. */ +struct gcry_ac_key_pair +{ + gcry_ac_key_t public; + gcry_ac_key_t secret; +}; + + + +/* + * Primitive functions for the manipulation of `data sets'. + */ + +/* Create a copy of the data set DATA and store it in DATA_CP. */ +static gcry_err_code_t +gcry_ac_data_copy_internal (gcry_ac_data_t *data_cp, gcry_ac_data_t data) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_ac_data_t data_new; + void *p = NULL; + int i = 0; + + /* Allocate data set. */ + err = _gcry_malloc (sizeof (struct gcry_ac_data), 0, &p); + data_new = p; + if (! err) + data_new->data_n = data->data_n; + + if (! err) + /* Allocate space for named MPIs. */ + err = _gcry_malloc (sizeof (gcry_ac_mpi_t) * data->data_n, 0, + (void **) &data_new->data); + + if (! err) + { + /* Copy named MPIs. */ + + for (i = 0; i < data_new->data_n && (! err); i++) + { + data_new->data[i].name = NULL; + data_new->data[i].mpi = NULL; + + /* Name. */ + data_new->data[i].name = strdup (data->data[i].name); + if (! data_new->data[i].name) + err = gpg_err_code_from_errno (errno); + + if (! err) + { + /* MPI. */ + data_new->data[i].mpi = gcry_mpi_copy (data->data[i].mpi); + if (! data_new->data[i].mpi) + err = gpg_err_code_from_errno (errno); + } + } + } + + if (! err) + { + /* Copy out. */ + *data_cp = data_new; + } + else + { + /* Deallocate resources. */ + if (data_new) + { + if (data_new->data) + { + for (; i >= 0; i--) + { + if (data_new->data[i].name) + free ((void *) data_new->data[i].name); + if (data_new->data[i].mpi) + gcry_mpi_release (data_new->data[i].mpi); + } + gcry_free (data_new->data); + } + gcry_free (data_new); + } + } + + return err; +} + + + +/* + * Functions for converting data between the native ac and the + * S-expression structure. + */ + +/* Extract the S-Expression DATA_SEXP into DATA under the control of + TYPE and NAME. This function assumes that S-Expressions are of the + following structure: + + (IDENTIFIER <data to be ignored> + (ALGORITHM <list of named MPI values>)) + + IDENTIFIER is one of `private-key', `public-key', `enc-val', + `sig-val'; ALGORITHM is the name of the algorithm used. */ +static gcry_err_code_t +gcry_ac_data_extract (const char *identifier, const char *algorithm, + gcry_sexp_t data_sexp, gcry_ac_data_t *data) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_sexp_t data_element_sexp = NULL; + gcry_sexp_t inner_data_sexp = NULL; + size_t inner_data_n; + + const char *name; + size_t name_n; + + gcry_mpi_t data_elem_mpi = NULL; + char *data_elem_name = NULL; + + gcry_ac_data_t data_new = NULL; + + int i = 0; + + /* Verify that the S-expression contains the correct identifier. */ + name = gcry_sexp_nth_data (data_sexp, 0, &name_n); + if (! name) + err = GPG_ERR_INTERNAL; + else if (strncmp (identifier, name, name_n)) + err = GPG_ERR_INTERNAL; + + if (! err) + { + /* Extract inner S-expression. */ + inner_data_sexp = gcry_sexp_find_token (data_sexp, algorithm, 0); + if (! inner_data_sexp) + err = GPG_ERR_INTERNAL; + else + /* Count data elements, this includes the name of the + algorithm. */ + inner_data_n = gcry_sexp_length (inner_data_sexp); + } + + if (! err) + { + /* Allocate new data set. */ + data_new = gcry_malloc (sizeof (struct gcry_ac_data)); + if (! data_new) + err = gpg_err_code_from_errno (errno); + else + { + data_new->data = gcry_malloc (sizeof (gcry_ac_mpi_t) + * (inner_data_n - 1)); + if (! data_new->data) + err = gpg_err_code_from_errno (errno); + } + } + + if (! err) + { + /* Iterate through list of data elements and add them to the + data set. */ + + for (i = 1; i < inner_data_n; i++) + { + data_new->data[i - 1].name = NULL; + data_new->data[i - 1].mpi = NULL; + + /* Get the S-expression of the named MPI, that contains the + name and the MPI value. */ + data_element_sexp = gcry_sexp_nth (inner_data_sexp, i); + if (! data_element_sexp) + err = GPG_ERR_INTERNAL; + + if (! err) + { + /* Extract the name. */ + name = gcry_sexp_nth_data (data_element_sexp, 0, &name_n); + if (! name) + err = GPG_ERR_INTERNAL; + } + + if (! err) + { + /* Extract the MPI value. */ + data_elem_mpi = gcry_sexp_nth_mpi (data_element_sexp, 1, + GCRYMPI_FMT_USG); + if (! data_elem_mpi) + err = GPG_ERR_INTERNAL; + } + + if (! err) + { + /* Duplicate the name. */ + data_elem_name = gcry_malloc (name_n + 1); + if (! data_elem_name) + + err = gpg_err_code_from_errno (errno); + else + { + strncpy (data_elem_name, name, name_n); + data_elem_name[name_n] = 0; + } + } + + /* Done. */ + + if (data_element_sexp) + gcry_sexp_release (data_element_sexp); + + if (! err) + { + data_new->data[i - 1].name = data_elem_name; + data_new->data[i - 1].mpi = data_elem_mpi; + } + else + break; + } + } + + if (! err) + { + /* Copy out. */ + data_new->data_n = inner_data_n - 1; + *data = data_new; + } + else + { + /* Deallocate resources. */ + + if (data_new) + { + if (data_new->data) + { + int j; + + for (j = 0; j < i - 1; j++) + { + if (data_new->data[j].name) + gcry_free ((void *) data_new->data[j].name); + if (data_new->data[j].mpi) + gcry_mpi_release (data_new->data[j].mpi); + } + + gcry_free (data_new->data); + } + gcry_free (data_new); + } + } + + return err; +} + +/* Construct an S-expression from the DATA and store it in + DATA_SEXP. The S-expression will be of the following structure: + + (IDENTIFIER [(flags [...])] + (ALGORITHM <list of named MPI values>)) */ +static gcry_err_code_t +gcry_ac_data_construct (const char *identifier, int include_flags, + unsigned int flags, const char *algorithm, + gcry_ac_data_t data, gcry_sexp_t *data_sexp) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + void **arg_list = NULL; + + gcry_sexp_t data_sexp_new = NULL; + + size_t data_format_n = 0; + char *data_format = NULL; + + int i; + + /* We build a list of arguments to pass to + gcry_sexp_build_array(). */ + arg_list = gcry_malloc (sizeof (void *) * data->data_n); + if (! arg_list) + err = gpg_err_code_from_errno (errno); + else + /* Fill list with MPIs. */ + for (i = 0; i < data->data_n; i++) + arg_list[i] = (void *) &data->data[i].mpi; + + if (! err) + { + /* Calculate size of format string. */ + + data_format_n = (5 + (include_flags ? 7 : 0) + + strlen (identifier) + strlen (algorithm)); + + for (i = 0; i < data->data_n; i++) + { + /* Per-element sizes. */ + data_format_n += 4 + strlen (data->data[i].name); + } + + if (include_flags) + { + /* Add flags. */ + for (i = 0; gcry_ac_flags[i].number; i++) + if (flags & gcry_ac_flags[i].number) + data_format_n += strlen (gcry_ac_flags[i].string) + 1; + } + + /* Done. */ + data_format = gcry_malloc (data_format_n); + if (! data_format) + err = gpg_err_code_from_errno (errno); + } + + if (! err) + { + /* Construct the format string. */ + + *data_format = 0; + strcat (data_format, "("); + strcat (data_format, identifier); + if (include_flags) + { + strcat (data_format, "(flags"); + for (i = 0; gcry_ac_flags[i].number; i++) + if (flags & gcry_ac_flags[i].number) + { + strcat (data_format, " "); + strcat (data_format, gcry_ac_flags[i].string); + } + strcat (data_format, ")"); + } + strcat (data_format, "("); + strcat (data_format, algorithm); + for (i = 0; i < data->data_n; i++) + { + strcat (data_format, "("); + strcat (data_format, data->data[i].name); + strcat (data_format, "%m)"); + } + strcat (data_format, "))"); + + /* Create final S-expression. */ + err = gcry_sexp_build_array (&data_sexp_new, NULL, + data_format, arg_list); + } + + if (err) + { + /* Deallocate resources. */ + + if (arg_list) + gcry_free (arg_list); + if (data_format) + gcry_free (data_format); + if (data_sexp_new) + gcry_sexp_release (data_sexp_new); + } + + else + /* Copy-out. */ + *data_sexp = data_sexp_new; + + return err; +} + + + +/* + * Functions for working with data sets. + */ + +/* Creates a new, empty data set and stores it in DATA. */ +gcry_error_t +gcry_ac_data_new (gcry_ac_data_t *data) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_ac_data_t data_new = NULL; + + data_new = gcry_malloc (sizeof (struct gcry_ac_data)); + if (! data_new) + err = gpg_err_code_from_errno (errno); + + if (! err) + { + data_new->data = NULL; + data_new->data_n = 0; + *data = data_new; + } + + return gcry_error (err); +} + +/* Destroys the data set DATA. */ +void +gcry_ac_data_destroy (gcry_ac_data_t data) +{ + int i; + + for (i = 0; i < data->data_n; i++) + { + gcry_free ((void *) data->data[i].name); + gcry_mpi_release (data->data[i].mpi); + } + gcry_free (data->data); + gcry_free (data); +} + +/* Add the value MPI to DATA with the label NAME. If FLAGS contains + GCRY_AC_FLAG_DATA_COPY, the data set will contain copies of NAME + and MPI. If FLAGS contains GCRY_AC_FLAG_DATA_DEALLOC or + GCRY_AC_FLAG_DATA_COPY, the values contained in the data set will + be deallocated when they are to be removed from the data set. */ +gcry_error_t +gcry_ac_data_set (gcry_ac_data_t data, unsigned int flags, + const char *name, gcry_mpi_t mpi) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_ac_mpi_t *ac_mpi = NULL; + gcry_mpi_t mpi_add = NULL; + char *name_add = NULL; + unsigned int i = 0; + + if (flags & ~(GCRY_AC_FLAG_DEALLOC | GCRY_AC_FLAG_COPY)) + err = GPG_ERR_INV_ARG; + else + { + if (flags & GCRY_AC_FLAG_COPY) + { + /* Create copies. */ + + name_add = strdup (name); + if (! name_add) + err = GPG_ERR_ENOMEM; + if (! err) + { + mpi_add = gcry_mpi_copy (mpi); + if (! mpi_add) + err = GPG_ERR_ENOMEM; + } + } + else + { + name_add = (char *) name; + mpi_add = mpi; + } + + /* Search for existing entry. */ + for (i = 0; (i < data->data_n) && (! ac_mpi); i++) + if (! strcmp (name, data->data[i].name)) + ac_mpi = data->data + i; + + if (ac_mpi) + { + /* An entry for NAME does already exist. */ + if (ac_mpi->flags & GCRY_AC_FLAG_DEALLOC) + { + /* Deallocate old values. */ + gcry_free ((char *) ac_mpi->name); + gcry_mpi_release (ac_mpi->mpi); + } + } + else + { + /* Create a new entry. */ + + gcry_ac_mpi_t *ac_mpis = NULL; + + ac_mpis = realloc (data->data, sizeof (*data->data) * (data->data_n + 1)); + if (! ac_mpis) + err = gpg_err_code_from_errno (errno); + + if (data->data != ac_mpis) + data->data = ac_mpis; + ac_mpi = data->data + data->data_n; + data->data_n++; + } + + ac_mpi->flags = flags; + ac_mpi->name = name_add; + ac_mpi->mpi = mpi_add; + } + + return gcry_error (err); +} + +/* Create a copy of the data set DATA and store it in DATA_CP. */ +gcry_error_t +gcry_ac_data_copy (gcry_ac_data_t *data_cp, gcry_ac_data_t data) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + + err = gcry_ac_data_copy_internal (data_cp, data); + + return gcry_error (err); +} + +/* Returns the number of named MPI values inside of the data set + DATA. */ +unsigned int +gcry_ac_data_length (gcry_ac_data_t data) +{ + return data->data_n; +} + +/* Store the value labelled with NAME found in DATA in MPI. If FLAGS + contains GCRY_AC_FLAG_COPY, store a copy of the MPI value contained + in the data set. MPI may be NULL. */ +gcry_error_t +gcry_ac_data_get_name (gcry_ac_data_t data, unsigned int flags, + const char *name, gcry_mpi_t *mpi) +{ + gcry_err_code_t err = GPG_ERR_NO_DATA; + gcry_mpi_t mpi_found = NULL; + unsigned int i = 0; + + if (flags & ~(GCRY_AC_FLAG_COPY)) + err = GPG_ERR_INV_ARG; + else + { + for (i = 0; i < data->data_n && (! mpi_found); i++) + if (! strcmp (data->data[i].name, name)) + { + if (flags & GCRY_AC_FLAG_COPY) + { + mpi_found = gcry_mpi_copy (data->data[i].mpi); + if (! mpi_found) + err = GPG_ERR_ENOMEM; + } + else + mpi_found = data->data[i].mpi; + + if (mpi_found) + err = GPG_ERR_NO_ERROR; + } + } + + if (! err) + if (mpi) + *mpi = mpi_found; + + return gcry_error (err); +} + +/* Stores in NAME and MPI the named MPI value contained in the data + set DATA with the index IDX. If FLAGS contains GCRY_AC_FLAG_COPY, + store copies of the values contained in the data set. NAME or MPI + may be NULL. */ +gcry_error_t +gcry_ac_data_get_index (gcry_ac_data_t data, unsigned int flags, unsigned int idx, + const char **name, gcry_mpi_t *mpi) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_mpi_t mpi_return = NULL; + char *name_return = NULL; + + if (flags & ~(GCRY_AC_FLAG_COPY)) + err = GPG_ERR_INV_ARG; + else + { + if (idx < data->data_n) + { + if (flags & GCRY_AC_FLAG_COPY) + { + /* Return copies to the user. */ + if (name) + name_return = strdup (data->data[idx].name); + if (mpi) + mpi_return = gcry_mpi_copy (data->data[idx].mpi); + + if (! (name_return && mpi_return)) + { + if (name_return) + free (name_return); + if (mpi_return) + gcry_mpi_release (mpi_return); + err = GPG_ERR_ENOMEM; + } + } + else + { + name_return = (char *) data->data[idx].name; + mpi_return = data->data[idx].mpi; + } + } + else + err = GPG_ERR_NO_DATA; + } + + if (! err) + { + if (name) + *name = name_return; + if (mpi) + *mpi = mpi_return; + } + + return gcry_error (err); +} + +/* Destroys any values contained in the data set DATA. */ +void +gcry_ac_data_clear (gcry_ac_data_t data) +{ + gcry_free (data->data); + data->data = NULL; + data->data_n = 0; +} + + + +/* + * Handle management. + */ + +/* Creates a new handle for the algorithm ALGORITHM and store it in + HANDLE. FLAGS is not used yet. */ +gcry_error_t +gcry_ac_open (gcry_ac_handle_t *handle, + gcry_ac_id_t algorithm, unsigned int flags) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_module_t module = NULL; + gcry_ac_handle_t handle_new; + const char *algorithm_name; + + *handle = NULL; + + /* Get name. */ + algorithm_name = _gcry_pk_aliased_algo_name (algorithm); + if (! *algorithm_name) + err = GPG_ERR_PUBKEY_ALGO; + + if (! err) /* Acquire reference to the pubkey module. */ + err = _gcry_pk_module_lookup (algorithm, &module); + + if (! err) + { + /* Allocate. */ + handle_new = gcry_malloc (sizeof (struct gcry_ac_handle)); + if (! handle_new) + err = gpg_err_code_from_errno (errno); + } + + if (! err) + { + /* Done. */ + handle_new->algorithm = algorithm; + handle_new->algorithm_name = algorithm_name; + handle_new->flags = flags; + handle_new->module = module; + *handle = handle_new; + } + else + { + /* Deallocate resources. */ + if (module) + _gcry_pk_module_release (module); + } + + return gcry_error (err); +} + +/* Destroys the handle HANDLE. */ +void +gcry_ac_close (gcry_ac_handle_t handle) +{ + /* Release reference to pubkey module. */ + if (handle) + { + _gcry_pk_module_release (handle->module); + gcry_free (handle); + } +} + + + +/* + * Key management. + */ + +/* Creates a new key of type TYPE, consisting of the MPI values + contained in the data set DATA and stores it in KEY. */ +gcry_error_t +gcry_ac_key_init (gcry_ac_key_t *key, + gcry_ac_handle_t handle, + gcry_ac_key_type_t type, + gcry_ac_data_t data) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_ac_data_t data_new = NULL; + gcry_sexp_t data_sexp = NULL; + gcry_ac_key_t key_new = NULL; + + /* Allocate. */ + key_new = gcry_malloc (sizeof (struct gcry_ac_key)); + if (! key_new) + err = gpg_err_code_from_errno (errno); + + if (! err) + { + /* Create S-expression from data set. */ + err = gcry_ac_data_construct (ac_key_identifiers[type], 0, 0, + handle->algorithm_name, data, &data_sexp); + } + + if (! err) + { + /* Copy data set. */ + err = gcry_ac_data_copy_internal (&data_new, data); + } + + if (! err) + { + /* Done. */ + key_new->data_sexp = data_sexp; + key_new->data = data_new; + key_new->type = type; + *key = key_new; + } + else + { + /* Deallocate resources. */ + if (key_new) + gcry_free (key_new); + if (data_sexp) + gcry_sexp_release (data_sexp); + } + + return gcry_error (err); +} + +/* Generates a new key pair via the handle HANDLE of NBITS bits and + stores it in KEY_PAIR. In case non-standard settings are wanted, a + pointer to a structure of type gcry_ac_key_spec_<algorithm>_t, + matching the selected algorithm, can be given as KEY_SPEC. + MISC_DATA is not used yet. */ +gcry_error_t +gcry_ac_key_pair_generate (gcry_ac_handle_t handle, unsigned int nbits, void *key_spec, + gcry_ac_key_pair_t *key_pair, gcry_mpi_t **misc_data) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + + gcry_ac_key_pair_t key_pair_new = NULL; + + gcry_sexp_t genkey_sexp_request = NULL; + gcry_sexp_t genkey_sexp_reply = NULL; + + char *genkey_format = NULL; + size_t genkey_format_n = 0; + + void **arg_list = NULL; + size_t arg_list_n = 0; + + unsigned int i = 0; + + /* Allocate key pair. */ + key_pair_new = gcry_malloc (sizeof (struct gcry_ac_key_pair)); + if (! key_pair_new) + err = gpg_err_code_from_errno (errno); + + if (! err) + { + /* Allocate keys. */ + key_pair_new->secret = gcry_malloc (sizeof (struct gcry_ac_key)); + key_pair_new->public = gcry_malloc (sizeof (struct gcry_ac_key)); + + if (! (key_pair_new->secret || key_pair_new->public)) + err = gpg_err_code_from_errno (errno); + else + { + key_pair_new->secret->type = GCRY_AC_KEY_SECRET; + key_pair_new->public->type = GCRY_AC_KEY_PUBLIC; + key_pair_new->secret->data_sexp = NULL; + key_pair_new->public->data_sexp = NULL; + key_pair_new->secret->data = NULL; + key_pair_new->public->data = NULL; + } + } + + if (! err) + { + /* Calculate size of the format string, that is used for + creating the request S-expression. */ + genkey_format_n = 23; + + /* Respect any relevant algorithm specific commands. */ + if (key_spec) + for (i = 0; gcry_ac_key_generate_specs[i].algorithm; i++) + if (handle->algorithm == gcry_ac_key_generate_specs[i].algorithm) + genkey_format_n += 6; + + /* Create format string. */ + genkey_format = gcry_malloc (genkey_format_n); + if (! genkey_format) + err = gpg_err_code_from_errno (errno); + else + { + /* Fill format string. */ + *genkey_format = 0; + strcat (genkey_format, "(genkey(%s(nbits%d)"); + if (key_spec) + for (i = 0; gcry_ac_key_generate_specs[i].algorithm; i++) + if (handle->algorithm == gcry_ac_key_generate_specs[i].algorithm) + strcat (genkey_format, "(%s%m)"); + strcat (genkey_format, "))"); + } + } + + if (! err) + { + /* Build list of argument pointers, the algorithm name and the + nbits are needed always. */ + arg_list_n = 2; + + /* Now the algorithm specific arguments. */ + if (key_spec) + for (i = 0; gcry_ac_key_generate_specs[i].algorithm; i++) + if (handle->algorithm == gcry_ac_key_generate_specs[i].algorithm) + arg_list_n += 2; + + /* Allocate list. */ + arg_list = gcry_malloc (sizeof (void *) * arg_list_n); + if (! arg_list) + err = gpg_err_code_from_errno (errno); + else + { + /* Fill argument list. */ + + int j; + + arg_list[0] = (void *) &handle->algorithm_name; + arg_list[1] = (void *) &nbits; + + if (key_spec) + for (j = 2, i = 0; gcry_ac_key_generate_specs[i].algorithm; i++) + if (handle->algorithm == gcry_ac_key_generate_specs[i].algorithm) + { + /* Add name of this specification flag and the + according member of the spec strucuture. */ + arg_list[j++] = (void *)(&gcry_ac_key_generate_specs[i].name); + arg_list[j++] = (void *) + (((char *) key_spec) + + gcry_ac_key_generate_specs[i].offset); + } + } + } + + if (! err) + /* Construct final request S-expression. */ + err = gcry_err_code (gcry_sexp_build_array (&genkey_sexp_request, NULL, + genkey_format, arg_list)); + + if (! err) + /* Perform genkey operation. */ + err = gcry_err_code (gcry_pk_genkey (&genkey_sexp_reply, + genkey_sexp_request)); + + /* Split keys. */ + if (! err) + { + key_pair_new->secret->data_sexp = gcry_sexp_find_token (genkey_sexp_reply, + "private-key", 0); + if (! key_pair_new->secret->data_sexp) + err = GPG_ERR_INTERNAL; + } + if (! err) + { + key_pair_new->public->data_sexp = gcry_sexp_find_token (genkey_sexp_reply, + "public-key", 0); + if (! key_pair_new->public->data_sexp) + err = GPG_ERR_INTERNAL; + } + + /* Extract key material. */ + if (! err) + err = gcry_ac_data_extract ("private-key", handle->algorithm_name, + key_pair_new->secret->data_sexp, + &key_pair_new->secret->data); + if (! err) + err = gcry_ac_data_extract ("public-key", handle->algorithm_name, + key_pair_new->public->data_sexp, + &key_pair_new->public->data); + + /* Done. */ + + if (! err) + *key_pair = key_pair_new; + else + { + /* Deallocate resources. */ + + if (key_pair_new) + { + if (key_pair_new->secret) + gcry_ac_key_destroy (key_pair_new->secret); + if (key_pair_new->public) + gcry_ac_key_destroy (key_pair_new->public); + + gcry_free (key_pair_new); + } + + if (arg_list) + gcry_free (arg_list); + + if (genkey_format) + gcry_free (genkey_format); + + if (genkey_sexp_request) + gcry_sexp_release (genkey_sexp_request); + if (genkey_sexp_reply) + gcry_sexp_release (genkey_sexp_reply); + } + + return gcry_error (err); +} + +/* Returns the key of type WHICH out of the key pair KEY_PAIR. */ +gcry_ac_key_t +gcry_ac_key_pair_extract (gcry_ac_key_pair_t key_pair, + gcry_ac_key_type_t witch) +{ + gcry_ac_key_t key = NULL; + + switch (witch) + { + case GCRY_AC_KEY_SECRET: + key = key_pair->secret; + break; + + case GCRY_AC_KEY_PUBLIC: + key = key_pair->public; + break; + } + + return key; +} + +/* Destroys the key KEY. */ +void +gcry_ac_key_destroy (gcry_ac_key_t key) +{ + int i; + + if (key) + { + if (key->data) + { + for (i = 0; i < key->data->data_n; i++) + if (key->data->data[i].mpi != NULL) + gcry_mpi_release (key->data->data[i].mpi); + gcry_free (key->data); + } + if (key->data_sexp) + gcry_sexp_release (key->data_sexp); + gcry_free (key); + } +} + +/* Destroys the key pair KEY_PAIR. */ +void +gcry_ac_key_pair_destroy (gcry_ac_key_pair_t key_pair) +{ + if (key_pair) + { + gcry_ac_key_destroy (key_pair->secret); + gcry_ac_key_destroy (key_pair->public); + gcry_free (key_pair); + } +} + +/* Returns the data set contained in the key KEY. */ +gcry_ac_data_t +gcry_ac_key_data_get (gcry_ac_key_t key) +{ + return key->data; +} + +/* Verifies that the key KEY is sane via HANDLE. */ +gcry_error_t +gcry_ac_key_test (gcry_ac_handle_t handle, gcry_ac_key_t key) +{ + gcry_err_code_t err; + + err = gcry_err_code (gcry_pk_testkey (key->data_sexp)); + + return gcry_error (err); +} + +/* Stores the number of bits of the key KEY in NBITS via HANDLE. */ +gcry_error_t +gcry_ac_key_get_nbits (gcry_ac_handle_t handle, gcry_ac_key_t key, unsigned int *nbits) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + unsigned int n; + + n = gcry_pk_get_nbits (key->data_sexp); + if (n) + *nbits = n; + else + err = GPG_ERR_PUBKEY_ALGO; + + return gcry_error (err); +} + +/* Writes the 20 byte long key grip of the key KEY to KEY_GRIP via + HANDLE. */ +gcry_error_t +gcry_ac_key_get_grip (gcry_ac_handle_t handle, gcry_ac_key_t key, unsigned char *key_grip) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + unsigned char *ret; + + ret = gcry_pk_get_keygrip (key->data_sexp, key_grip); + if (! ret) + err = GPG_ERR_INV_OBJ; + + return gcry_error (err); +} + + + +/* + * Functions performing cryptographic operations. + */ + +/* Encrypts the plain text MPI value DATA_PLAIN with the key public + KEY under the control of the flags FLAGS and stores the resulting + data set into DATA_ENCRYPTED. */ +gcry_error_t +gcry_ac_data_encrypt (gcry_ac_handle_t handle, + unsigned int flags, + gcry_ac_key_t key, + gcry_mpi_t data_plain, + gcry_ac_data_t *data_encrypted) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_sexp_t sexp_request = NULL; + gcry_sexp_t sexp_reply = NULL; + char *request_format = NULL; + size_t request_format_n = 0; + gcry_ac_data_t data; + + int i; + + if (key->type != GCRY_AC_KEY_PUBLIC) + err = GPG_ERR_WRONG_KEY_USAGE; + + if (! err) + { + /* Calculate request format string. */ + + request_format_n += 23; + for (i = 0; gcry_ac_flags[i].number; i++) + if (flags & gcry_ac_flags[i].number) + request_format_n += strlen (gcry_ac_flags[i].string) + 1; + + /* Allocate request format string. */ + request_format = gcry_malloc (request_format_n); + if (! request_format) + err = gpg_err_code_from_errno (errno); + } + + if (! err) + { + /* Fill format string. */ + *request_format = 0; + strcat (request_format, "(data(flags"); + for (i = 0; gcry_ac_flags[i].number; i++) + if (flags & gcry_ac_flags[i].number) + { + strcat (request_format, " "); + strcat (request_format, gcry_ac_flags[i].string); + } + strcat (request_format, ")(value%m))"); + + /* Create S-expression. */ + err = gcry_sexp_build (&sexp_request, NULL, + request_format, data_plain); + } + + if (! err) + /* Encrypt. */ + err = gcry_pk_encrypt (&sexp_reply, sexp_request, key->data_sexp); + + if (! err) + /* Extract data. */ + err = gcry_ac_data_extract ("enc-val", handle->algorithm_name, + sexp_reply, &data); + + /* Deallocate resources. */ + + if (sexp_request) + gcry_sexp_release (sexp_request); + if (sexp_reply) + gcry_sexp_release (sexp_reply); + + if (! err) + /* Copy out. */ + *data_encrypted = data; + + return gcry_error (err); +} + +/* Decrypts the encrypted data contained in the data set + DATA_ENCRYPTED with the secret key KEY under the control of the + flags FLAGS and stores the resulting plain text MPI value in + DATA_PLAIN. */ +gcry_error_t +gcry_ac_data_decrypt (gcry_ac_handle_t handle, + unsigned int flags, + gcry_ac_key_t key, + gcry_mpi_t *data_plain, + gcry_ac_data_t data_encrypted) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_mpi_t data_decrypted = NULL; + gcry_sexp_t sexp_request = NULL; + gcry_sexp_t sexp_reply = NULL; + + if (key->type != GCRY_AC_KEY_SECRET) + err = GPG_ERR_WRONG_KEY_USAGE; + + if (! err) + /* Create S-expression from data. */ + err = gcry_ac_data_construct ("enc-val", 1, flags, handle->algorithm_name, + data_encrypted, &sexp_request); + + if (! err) + /* Decrypt. */ + err = gcry_pk_decrypt (&sexp_reply, sexp_request, key->data_sexp); + + if (! err) + { + /* Extract plain text. */ + + gcry_sexp_t l; + + l = gcry_sexp_find_token (sexp_reply, "value", 0); + if (! l) + err = GPG_ERR_GENERAL; + else + { + data_decrypted = gcry_sexp_nth_mpi (l, 1, GCRYMPI_FMT_USG); + if (! data_decrypted) + err = GPG_ERR_GENERAL; + gcry_sexp_release (l); + } + } + + /* Done. */ + + if (err) + { + /* Deallocate resources. */ + if (sexp_request) + gcry_sexp_release (sexp_request); + if (sexp_reply) + gcry_sexp_release (sexp_reply); + } + else + *data_plain = data_decrypted; + + return gcry_error (err); + +} + +/* Signs the data contained in DATA with the secret key KEY and stores + the resulting signature data set in DATA_SIGNATURE. */ +gcry_error_t +gcry_ac_data_sign (gcry_ac_handle_t handle, + gcry_ac_key_t key, + gcry_mpi_t data, + gcry_ac_data_t *data_signature) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_sexp_t sexp_request = NULL; + gcry_sexp_t sexp_reply = NULL; + gcry_ac_data_t ac_data; + + if (key->type != GCRY_AC_KEY_SECRET) + err = GPG_ERR_WRONG_KEY_USAGE; + + if (! err) + /* Create S-expression holding the data. */ + err = gcry_sexp_build (&sexp_request, NULL, + "(data(flags)(value%m))", data); + if (! err) + /* Sign. */ + err = gcry_pk_sign (&sexp_reply, sexp_request, key->data_sexp); + + if (! err) + /* Extract data. */ + err = gcry_ac_data_extract ("sig-val", handle->algorithm_name, + sexp_reply, &ac_data); + + /* Done. */ + + if (sexp_request) + gcry_sexp_release (sexp_request); + if (sexp_reply) + gcry_sexp_release (sexp_reply); + + if (! err) + *data_signature = ac_data; + + return gcry_error (err); +} + +/* Verifies that the signature contained in the data set + DATA_SIGNATURE is indeed the result of signing the data contained + in DATA with the secret key belonging to the public key KEY. */ +gcry_error_t +gcry_ac_data_verify (gcry_ac_handle_t handle, + gcry_ac_key_t key, + gcry_mpi_t data, + gcry_ac_data_t data_signature) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_sexp_t sexp_request = NULL; + gcry_sexp_t sexp_data = NULL; + + if (key->type != GCRY_AC_KEY_PUBLIC) + err = GPG_ERR_WRONG_KEY_USAGE; + + if (! err) + /* Construct S-expression holding the signature data. */ + err = gcry_ac_data_construct ("sig-val", 1, 0, handle->algorithm_name, + data_signature, &sexp_request); + + if (! err) + /* Construct S-expression holding the data. */ + err = gcry_sexp_build (&sexp_data, NULL, + "(data(flags)(value%m))", data); + + if (! err) + /* Verify signature. */ + err = gcry_pk_verify (sexp_request, sexp_data, key->data_sexp); + + /* Done. */ + + if (sexp_request) + gcry_sexp_release (sexp_request); + if (sexp_data) + gcry_sexp_release (sexp_data); + + return gcry_error (err); +} + + + +/* + * General functions. + */ + +/* Stores the textual representation of the algorithm whose id is + given in ALGORITHM in NAME. */ +gcry_error_t +gcry_ac_id_to_name (gcry_ac_id_t algorithm, const char **name) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + const char *n; + + n = gcry_pk_algo_name (algorithm); + if (*n) + *name = n; + else + err = GPG_ERR_PUBKEY_ALGO; + + return gcry_error (err); +} + +/* Stores the numeric ID of the algorithm whose textual representation + is contained in NAME in ALGORITHM. */ +gcry_error_t +gcry_ac_name_to_id (const char *name, gcry_ac_id_t *algorithm) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + int algo; + + algo = gcry_pk_map_name (name); + if (algo) + *algorithm = algo; + else + err = GPG_ERR_PUBKEY_ALGO; + + return gcry_error (err); +} |