summaryrefslogtreecommitdiffabout
path: root/pwmanager/libcrypt/cipher/ac.c
Side-by-side diff
Diffstat (limited to 'pwmanager/libcrypt/cipher/ac.c') (more/less context) (ignore whitespace changes)
-rw-r--r--pwmanager/libcrypt/cipher/ac.c1390
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);
+}