diff options
Diffstat (limited to 'plugins/MirOTR/Libgcrypt/cipher/ac.c')
-rw-r--r-- | plugins/MirOTR/Libgcrypt/cipher/ac.c | 3301 |
1 files changed, 0 insertions, 3301 deletions
diff --git a/plugins/MirOTR/Libgcrypt/cipher/ac.c b/plugins/MirOTR/Libgcrypt/cipher/ac.c deleted file mode 100644 index ee9498b23d..0000000000 --- a/plugins/MirOTR/Libgcrypt/cipher/ac.c +++ /dev/null @@ -1,3301 +0,0 @@ -/* ac.c - Alternative interface for asymmetric cryptography. - Copyright (C) 2003, 2004, 2005, 2006 - 2007, 2008 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, see <http://www.gnu.org/licenses/>. - */ - -#include <config.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <stddef.h> - -#include "g10lib.h" -#include "cipher.h" -#include "mpi.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 many people prefer the ac interface. */ - -/* Mapping of flag numbers to the according strings as it is expected - for S-expressions. */ -static struct number_string -{ - int number; - const char *string; -} ac_flags[] = - { - { GCRY_AC_FLAG_NO_BLINDING, "no-blinding" }, - }; - -/* 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. */ -} 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 -{ - char *name; /* Self-maintained copy of name. */ - 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. */ -}; - -/* A single key. */ -struct gcry_ac_key -{ - gcry_ac_data_t data; /* Data in native ac structure. */ - gcry_ac_key_type_t type; /* Type of the key. */ -}; - -/* A key pair. */ -struct gcry_ac_key_pair -{ - gcry_ac_key_t public; - gcry_ac_key_t secret; -}; - - - -/* - * Functions for working with data sets. - */ - -/* Creates a new, empty data set and store it in DATA. */ -gcry_error_t -_gcry_ac_data_new (gcry_ac_data_t *data) -{ - gcry_ac_data_t data_new; - gcry_error_t err; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - data_new = gcry_malloc (sizeof (*data_new)); - if (! data_new) - { - err = gcry_error_from_errno (errno); - goto out; - } - - data_new->data = NULL; - data_new->data_n = 0; - *data = data_new; - err = 0; - - out: - - return err; -} - -/* Destroys all the entries in DATA, but not DATA itself. */ -static void -ac_data_values_destroy (gcry_ac_data_t data) -{ - unsigned int i; - - for (i = 0; i < data->data_n; i++) - if (data->data[i].flags & GCRY_AC_FLAG_DEALLOC) - { - gcry_mpi_release (data->data[i].mpi); - gcry_free (data->data[i].name); - } -} - -/* Destroys the data set DATA. */ -void -_gcry_ac_data_destroy (gcry_ac_data_t data) -{ - if (data) - { - ac_data_values_destroy (data); - gcry_free (data->data); - gcry_free (data); - } -} - -/* This function creates a copy of the array of named MPIs DATA_MPIS, - which is of length DATA_MPIS_N; the copy is stored in - DATA_MPIS_CP. */ -static gcry_error_t -ac_data_mpi_copy (gcry_ac_mpi_t *data_mpis, unsigned int data_mpis_n, - gcry_ac_mpi_t **data_mpis_cp) -{ - gcry_ac_mpi_t *data_mpis_new; - gcry_error_t err; - unsigned int i; - gcry_mpi_t mpi; - char *label; - - data_mpis_new = gcry_malloc (sizeof (*data_mpis_new) * data_mpis_n); - if (! data_mpis_new) - { - err = gcry_error_from_errno (errno); - goto out; - } - memset (data_mpis_new, 0, sizeof (*data_mpis_new) * data_mpis_n); - - err = 0; - for (i = 0; i < data_mpis_n; i++) - { - /* Copy values. */ - - label = gcry_strdup (data_mpis[i].name); - mpi = gcry_mpi_copy (data_mpis[i].mpi); - if (! (label && mpi)) - { - err = gcry_error_from_errno (errno); - gcry_mpi_release (mpi); - gcry_free (label); - break; - } - - data_mpis_new[i].flags = GCRY_AC_FLAG_DEALLOC; - data_mpis_new[i].name = label; - data_mpis_new[i].mpi = mpi; - } - if (err) - goto out; - - *data_mpis_cp = data_mpis_new; - err = 0; - - out: - - if (err) - if (data_mpis_new) - { - for (i = 0; i < data_mpis_n; i++) - { - gcry_mpi_release (data_mpis_new[i].mpi); - gcry_free (data_mpis_new[i].name); - } - gcry_free (data_mpis_new); - } - - return 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_ac_mpi_t *data_mpis = NULL; - gcry_ac_data_t data_new; - gcry_error_t err; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - /* Allocate data set. */ - data_new = gcry_malloc (sizeof (*data_new)); - if (! data_new) - { - err = gcry_error_from_errno (errno); - goto out; - } - - err = ac_data_mpi_copy (data->data, data->data_n, &data_mpis); - if (err) - goto out; - - data_new->data_n = data->data_n; - data_new->data = data_mpis; - *data_cp = data_new; - - out: - - if (err) - gcry_free (data_new); - - return 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; -} - - -/* Add the value MPI to DATA with the label NAME. If FLAGS contains - GCRY_AC_FLAG_COPY, the data set will contain copies of NAME - and MPI. If FLAGS contains GCRY_AC_FLAG_DEALLOC or - GCRY_AC_FLAG_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_error_t err; - gcry_mpi_t mpi_cp; - char *name_cp; - unsigned int i; - - name_cp = NULL; - mpi_cp = NULL; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - if (flags & ~(GCRY_AC_FLAG_DEALLOC | GCRY_AC_FLAG_COPY)) - { - err = gcry_error (GPG_ERR_INV_ARG); - goto out; - } - - if (flags & GCRY_AC_FLAG_COPY) - { - /* Create copies. */ - - flags |= GCRY_AC_FLAG_DEALLOC; - name_cp = gcry_strdup (name); - mpi_cp = gcry_mpi_copy (mpi); - if (! (name_cp && mpi_cp)) - { - err = gcry_error_from_errno (errno); - goto out; - } - } - - /* Search for existing entry. */ - for (i = 0; i < data->data_n; i++) - if (! strcmp (name, data->data[i].name)) - break; - if (i < data->data_n) - { - /* An entry for NAME does already exist. */ - if (data->data[i].flags & GCRY_AC_FLAG_DEALLOC) - { - gcry_mpi_release (data->data[i].mpi); - gcry_free (data->data[i].name); - } - } - else - { - /* Create a new entry. */ - - gcry_ac_mpi_t *ac_mpis; - - ac_mpis = gcry_realloc (data->data, - sizeof (*data->data) * (data->data_n + 1)); - if (! ac_mpis) - { - err = gcry_error_from_errno (errno); - goto out; - } - - if (data->data != ac_mpis) - data->data = ac_mpis; - data->data_n++; - } - - data->data[i].name = name_cp ? name_cp : ((char *) name); - data->data[i].mpi = mpi_cp ? mpi_cp : mpi; - data->data[i].flags = flags; - err = 0; - - out: - - if (err) - { - gcry_mpi_release (mpi_cp); - gcry_free (name_cp); - } - - return err; -} - -/* Stores the value labelled with NAME found in the data set DATA in - MPI. The returned MPI value will be released in case - gcry_ac_data_set is used to associate the label NAME with a - different MPI value. */ -gcry_error_t -_gcry_ac_data_get_name (gcry_ac_data_t data, unsigned int flags, - const char *name, gcry_mpi_t *mpi) -{ - gcry_mpi_t mpi_return; - gcry_error_t err; - unsigned int i; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - if (flags & ~(GCRY_AC_FLAG_COPY)) - { - err = gcry_error (GPG_ERR_INV_ARG); - goto out; - } - - for (i = 0; i < data->data_n; i++) - if (! strcmp (name, data->data[i].name)) - break; - if (i == data->data_n) - { - err = gcry_error (GPG_ERR_NOT_FOUND); - goto out; - } - - if (flags & GCRY_AC_FLAG_COPY) - { - mpi_return = gcry_mpi_copy (data->data[i].mpi); - if (! mpi_return) - { - err = gcry_error_from_errno (errno); /* FIXME? */ - goto out; - } - } - else - mpi_return = data->data[i].mpi; - - *mpi = mpi_return; - err = 0; - - out: - - return err; -} - -/* Stores in NAME and MPI the named MPI value contained in the data - set DATA with the index IDX. NAME or MPI may be NULL. The - returned MPI value will be released in case gcry_ac_data_set is - used to associate the label NAME with a different MPI value. */ -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_error_t err; - gcry_mpi_t mpi_cp; - char *name_cp; - - name_cp = NULL; - mpi_cp = NULL; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - if (flags & ~(GCRY_AC_FLAG_COPY)) - { - err = gcry_error (GPG_ERR_INV_ARG); - goto out; - } - - if (idx >= data->data_n) - { - err = gcry_error (GPG_ERR_INV_ARG); - goto out; - } - - if (flags & GCRY_AC_FLAG_COPY) - { - /* Return copies to the user. */ - if (name) - { - name_cp = gcry_strdup (data->data[idx].name); - if (! name_cp) - { - err = gcry_error_from_errno (errno); - goto out; - } - } - if (mpi) - { - mpi_cp = gcry_mpi_copy (data->data[idx].mpi); - if (! mpi_cp) - { - err = gcry_error_from_errno (errno); - goto out; - } - } - } - - if (name) - *name = name_cp ? name_cp : data->data[idx].name; - if (mpi) - *mpi = mpi_cp ? mpi_cp : data->data[idx].mpi; - err = 0; - - out: - - if (err) - { - gcry_mpi_release (mpi_cp); - gcry_free (name_cp); - } - - return err; -} - -/* Convert the data set DATA into a new S-Expression, which is to be - stored in SEXP, according to the identifiers contained in - IDENTIFIERS. */ -gcry_error_t -_gcry_ac_data_to_sexp (gcry_ac_data_t data, gcry_sexp_t *sexp, - const char **identifiers) -{ - gcry_sexp_t sexp_new; - gcry_error_t err; - char *sexp_buffer; - size_t sexp_buffer_n; - size_t identifiers_n; - const char *label; - gcry_mpi_t mpi; - void **arg_list; - size_t data_n; - unsigned int i; - - sexp_buffer_n = 1; - sexp_buffer = NULL; - arg_list = NULL; - err = 0; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - /* Calculate size of S-expression representation. */ - - i = 0; - if (identifiers) - while (identifiers[i]) - { - /* For each identifier, we add "(<IDENTIFIER>)". */ - sexp_buffer_n += 1 + strlen (identifiers[i]) + 1; - i++; - } - identifiers_n = i; - - if (! identifiers_n) - /* If there are NO identifiers, we still add surrounding braces so - that we have a list of named MPI value lists. Otherwise it - wouldn't be too much fun to process these lists. */ - sexp_buffer_n += 2; - - data_n = _gcry_ac_data_length (data); - for (i = 0; i < data_n; i++) - { - err = gcry_ac_data_get_index (data, 0, i, &label, NULL); - if (err) - break; - /* For each MPI we add "(<LABEL> %m)". */ - sexp_buffer_n += 1 + strlen (label) + 4; - } - if (err) - goto out; - - /* Allocate buffer. */ - - sexp_buffer = gcry_malloc (sexp_buffer_n); - if (! sexp_buffer) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Fill buffer. */ - - *sexp_buffer = 0; - sexp_buffer_n = 0; - - /* Add identifiers: (<IDENTIFIER0>(<IDENTIFIER1>...)). */ - if (identifiers_n) - { - /* Add nested identifier lists as usual. */ - for (i = 0; i < identifiers_n; i++) - sexp_buffer_n += sprintf (sexp_buffer + sexp_buffer_n, "(%s", - identifiers[i]); - } - else - { - /* Add special list. */ - sexp_buffer_n += sprintf (sexp_buffer + sexp_buffer_n, "("); - } - - /* Add MPI list. */ - arg_list = gcry_malloc (sizeof (*arg_list) * (data_n + 1)); - if (! arg_list) - { - err = gcry_error_from_errno (errno); - goto out; - } - for (i = 0; i < data_n; i++) - { - err = gcry_ac_data_get_index (data, 0, i, &label, &mpi); - if (err) - break; - sexp_buffer_n += sprintf (sexp_buffer + sexp_buffer_n, - "(%s %%m)", label); - arg_list[i] = &data->data[i].mpi; - } - if (err) - goto out; - - if (identifiers_n) - { - /* Add closing braces for identifier lists as usual. */ - for (i = 0; i < identifiers_n; i++) - sexp_buffer_n += sprintf (sexp_buffer + sexp_buffer_n, ")"); - } - else - { - /* Add closing braces for special list. */ - sexp_buffer_n += sprintf (sexp_buffer + sexp_buffer_n, ")"); - } - - /* Construct. */ - err = gcry_sexp_build_array (&sexp_new, NULL, sexp_buffer, arg_list); - if (err) - goto out; - - *sexp = sexp_new; - - out: - - gcry_free (sexp_buffer); - gcry_free (arg_list); - - return err; -} - -/* Create a new data set, which is to be stored in DATA_SET, from the - S-Expression SEXP, according to the identifiers contained in - IDENTIFIERS. */ -gcry_error_t -_gcry_ac_data_from_sexp (gcry_ac_data_t *data_set, gcry_sexp_t sexp, - const char **identifiers) -{ - gcry_ac_data_t data_set_new; - gcry_error_t err; - gcry_sexp_t sexp_cur; - gcry_sexp_t sexp_tmp; - gcry_mpi_t mpi; - char *string; - const char *data; - size_t data_n; - size_t sexp_n; - unsigned int i; - int skip_name; - - data_set_new = NULL; - sexp_cur = sexp; - sexp_tmp = NULL; - string = NULL; - mpi = NULL; - err = 0; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - /* Process S-expression/identifiers. */ - - if (identifiers) - { - for (i = 0; identifiers[i]; i++) - { - /* Next identifier. Extract first data item from - SEXP_CUR. */ - data = gcry_sexp_nth_data (sexp_cur, 0, &data_n); - - if (! ((data_n == strlen (identifiers[i])) - && (! strncmp (data, identifiers[i], data_n)))) - { - /* Identifier mismatch -> error. */ - err = gcry_error (GPG_ERR_INV_SEXP); - break; - } - - /* Identifier matches. Now we have to distinguish two - cases: - - (i) we are at the last identifier: - leave loop - - (ii) we are not at the last identifier: - extract next element, which is supposed to be a - sublist. */ - - if (! identifiers[i + 1]) - /* Last identifier. */ - break; - else - { - /* Not the last identifier, extract next sublist. */ - - sexp_tmp = gcry_sexp_nth (sexp_cur, 1); - if (! sexp_tmp) - { - /* Missing sublist. */ - err = gcry_error (GPG_ERR_INV_SEXP); - break; - } - - /* Release old SEXP_CUR, in case it is not equal to the - original SEXP. */ - if (sexp_cur != sexp) - gcry_sexp_release (sexp_cur); - - /* Make SEXP_CUR point to the new current sublist. */ - sexp_cur = sexp_tmp; - sexp_tmp = NULL; - } - } - if (err) - goto out; - - if (i) - { - /* We have at least one identifier in the list, this means - the the list of named MPI values is prefixed, this means - that we need to skip the first item (the list name), when - processing the MPI values. */ - skip_name = 1; - } - else - { - /* Since there is no identifiers list, the list of named MPI - values is not prefixed with a list name, therefore the - offset to use is zero. */ - skip_name = 0; - } - } - else - /* Since there is no identifiers list, the list of named MPI - values is not prefixed with a list name, therefore the offset - to use is zero. */ - skip_name = 0; - - /* Create data set from S-expression data. */ - - err = gcry_ac_data_new (&data_set_new); - if (err) - goto out; - - /* Figure out amount of named MPIs in SEXP_CUR. */ - if (sexp_cur) - sexp_n = gcry_sexp_length (sexp_cur) - skip_name; - else - sexp_n = 0; - - /* Extracte the named MPIs sequentially. */ - for (i = 0; i < sexp_n; i++) - { - /* Store next S-Expression pair, which is supposed to consist of - a name and an MPI value, in SEXP_TMP. */ - - sexp_tmp = gcry_sexp_nth (sexp_cur, i + skip_name); - if (! sexp_tmp) - { - err = gcry_error (GPG_ERR_INV_SEXP); - break; - } - - /* Extract name from current S-Expression pair. */ - data = gcry_sexp_nth_data (sexp_tmp, 0, &data_n); - string = gcry_malloc (data_n + 1); - if (! string) - { - err = gcry_error_from_errno (errno); - break; - } - memcpy (string, data, data_n); - string[data_n] = 0; - - /* Extract MPI value. */ - mpi = gcry_sexp_nth_mpi (sexp_tmp, 1, 0); - if (! mpi) - { - err = gcry_error (GPG_ERR_INV_SEXP); /* FIXME? */ - break; - } - - /* Store named MPI in data_set_new. */ - err = gcry_ac_data_set (data_set_new, GCRY_AC_FLAG_DEALLOC, string, mpi); - if (err) - break; - -/* gcry_free (string); */ - string = NULL; -/* gcry_mpi_release (mpi); */ - mpi = NULL; - - gcry_sexp_release (sexp_tmp); - sexp_tmp = NULL; - } - if (err) - goto out; - - *data_set = data_set_new; - - out: - - if (sexp_cur != sexp) - gcry_sexp_release (sexp_cur); - gcry_sexp_release (sexp_tmp); - gcry_mpi_release (mpi); - gcry_free (string); - - if (err) - gcry_ac_data_destroy (data_set_new); - - return err; -} - - -static void -_gcry_ac_data_dump (const char *prefix, gcry_ac_data_t data) -{ - unsigned char *mpi_buffer; - size_t mpi_buffer_n; - unsigned int data_n; - gcry_error_t err; - const char *name; - gcry_mpi_t mpi; - unsigned int i; - - if (! data) - return; - - if (fips_mode ()) - return; - - mpi_buffer = NULL; - - data_n = _gcry_ac_data_length (data); - for (i = 0; i < data_n; i++) - { - err = gcry_ac_data_get_index (data, 0, i, &name, &mpi); - if (err) - { - log_error ("failed to dump data set"); - break; - } - - err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &mpi_buffer, &mpi_buffer_n, mpi); - if (err) - { - log_error ("failed to dump data set"); - break; - } - - log_printf ("%s%s%s: %s\n", - prefix ? prefix : "", - prefix ? ": " : "" - , name, mpi_buffer); - - gcry_free (mpi_buffer); - mpi_buffer = NULL; - } - - gcry_free (mpi_buffer); -} - -/* Dump the named MPI values contained in the data set DATA to - Libgcrypt's logging stream. */ -void -gcry_ac_data_dump (const char *prefix, gcry_ac_data_t data) -{ - _gcry_ac_data_dump (prefix, data); -} - -/* Destroys any values contained in the data set DATA. */ -void -_gcry_ac_data_clear (gcry_ac_data_t data) -{ - ac_data_values_destroy (data); - gcry_free (data->data); - data->data = NULL; - data->data_n = 0; -} - - - -/* - * Implementation of `ac io' objects. - */ - -/* Initialize AC_IO according to MODE, TYPE and the variable list of - arguments AP. The list of variable arguments to specify depends on - the given TYPE. */ -void -_gcry_ac_io_init_va (gcry_ac_io_t *ac_io, - gcry_ac_io_mode_t mode, gcry_ac_io_type_t type, va_list ap) -{ - memset (ac_io, 0, sizeof (*ac_io)); - - if (fips_mode ()) - return; - - gcry_assert ((mode == GCRY_AC_IO_READABLE) || (mode == GCRY_AC_IO_WRITABLE)); - gcry_assert ((type == GCRY_AC_IO_STRING) || (type == GCRY_AC_IO_STRING)); - - ac_io->mode = mode; - ac_io->type = type; - - switch (mode) - { - case GCRY_AC_IO_READABLE: - switch (type) - { - case GCRY_AC_IO_STRING: - ac_io->io.readable.string.data = va_arg (ap, unsigned char *); - ac_io->io.readable.string.data_n = va_arg (ap, size_t); - break; - - case GCRY_AC_IO_CALLBACK: - ac_io->io.readable.callback.cb = va_arg (ap, gcry_ac_data_read_cb_t); - ac_io->io.readable.callback.opaque = va_arg (ap, void *); - break; - } - break; - case GCRY_AC_IO_WRITABLE: - switch (type) - { - case GCRY_AC_IO_STRING: - ac_io->io.writable.string.data = va_arg (ap, unsigned char **); - ac_io->io.writable.string.data_n = va_arg (ap, size_t *); - break; - - case GCRY_AC_IO_CALLBACK: - ac_io->io.writable.callback.cb = va_arg (ap, gcry_ac_data_write_cb_t); - ac_io->io.writable.callback.opaque = va_arg (ap, void *); - break; - } - break; - } -} - -/* Initialize AC_IO according to MODE, TYPE and the variable list of - arguments. The list of variable arguments to specify depends on - the given TYPE. */ -void -_gcry_ac_io_init (gcry_ac_io_t *ac_io, - gcry_ac_io_mode_t mode, gcry_ac_io_type_t type, ...) -{ - va_list ap; - - va_start (ap, type); - _gcry_ac_io_init_va (ac_io, mode, type, ap); - va_end (ap); -} - - -/* Write to the IO object AC_IO BUFFER_N bytes from BUFFER. Return - zero on success or error code. */ -static gcry_error_t -_gcry_ac_io_write (gcry_ac_io_t *ac_io, unsigned char *buffer, size_t buffer_n) -{ - gcry_error_t err; - - gcry_assert (ac_io->mode == GCRY_AC_IO_WRITABLE); - err = 0; - - switch (ac_io->type) - { - case GCRY_AC_IO_STRING: - { - unsigned char *p; - - if (*ac_io->io.writable.string.data) - { - p = gcry_realloc (*ac_io->io.writable.string.data, - *ac_io->io.writable.string.data_n + buffer_n); - if (! p) - err = gcry_error_from_errno (errno); - else - { - if (*ac_io->io.writable.string.data != p) - *ac_io->io.writable.string.data = p; - memcpy (p + *ac_io->io.writable.string.data_n, buffer, buffer_n); - *ac_io->io.writable.string.data_n += buffer_n; - } - } - else - { - if (gcry_is_secure (buffer)) - p = gcry_malloc_secure (buffer_n); - else - p = gcry_malloc (buffer_n); - if (! p) - err = gcry_error_from_errno (errno); - else - { - memcpy (p, buffer, buffer_n); - *ac_io->io.writable.string.data = p; - *ac_io->io.writable.string.data_n = buffer_n; - } - } - } - break; - - case GCRY_AC_IO_CALLBACK: - err = (*ac_io->io.writable.callback.cb) (ac_io->io.writable.callback.opaque, - buffer, buffer_n); - break; - } - - return err; -} - -/* Read *BUFFER_N bytes from the IO object AC_IO into BUFFER; NREAD - bytes have already been read from the object; on success, store the - amount of bytes read in *BUFFER_N; zero bytes read means EOF. - Return zero on success or error code. */ -static gcry_error_t -_gcry_ac_io_read (gcry_ac_io_t *ac_io, - unsigned int nread, unsigned char *buffer, size_t *buffer_n) -{ - gcry_error_t err; - - gcry_assert (ac_io->mode == GCRY_AC_IO_READABLE); - err = 0; - - switch (ac_io->type) - { - case GCRY_AC_IO_STRING: - { - size_t bytes_available; - size_t bytes_to_read; - size_t bytes_wanted; - - bytes_available = ac_io->io.readable.string.data_n - nread; - bytes_wanted = *buffer_n; - - if (bytes_wanted > bytes_available) - bytes_to_read = bytes_available; - else - bytes_to_read = bytes_wanted; - - memcpy (buffer, ac_io->io.readable.string.data + nread, bytes_to_read); - *buffer_n = bytes_to_read; - err = 0; - break; - } - - case GCRY_AC_IO_CALLBACK: - err = (*ac_io->io.readable.callback.cb) - (ac_io->io.readable.callback.opaque, buffer, buffer_n); - break; - } - - return err; -} - -/* Read all data available from the IO object AC_IO into newly - allocated memory, storing an appropriate pointer in *BUFFER and the - amount of bytes read in *BUFFER_N. Return zero on success or error - code. */ -static gcry_error_t -_gcry_ac_io_read_all (gcry_ac_io_t *ac_io, unsigned char **buffer, size_t *buffer_n) -{ - unsigned char *buffer_new; - size_t buffer_new_n; - unsigned char buf[BUFSIZ]; - size_t buf_n; - unsigned char *p; - gcry_error_t err; - - buffer_new = NULL; - buffer_new_n = 0; - - while (1) - { - buf_n = sizeof (buf); - err = _gcry_ac_io_read (ac_io, buffer_new_n, buf, &buf_n); - if (err) - break; - - if (buf_n) - { - p = gcry_realloc (buffer_new, buffer_new_n + buf_n); - if (! p) - { - err = gcry_error_from_errno (errno); - break; - } - - if (buffer_new != p) - buffer_new = p; - - memcpy (buffer_new + buffer_new_n, buf, buf_n); - buffer_new_n += buf_n; - } - else - break; - } - if (err) - goto out; - - *buffer_n = buffer_new_n; - *buffer = buffer_new; - - out: - - if (err) - gcry_free (buffer_new); - - return err; -} - -/* Read data chunks from the IO object AC_IO until EOF, feeding them - to the callback function CB. Return zero on success or error - code. */ -static gcry_error_t -_gcry_ac_io_process (gcry_ac_io_t *ac_io, - gcry_ac_data_write_cb_t cb, void *opaque) -{ - unsigned char buffer[BUFSIZ]; - unsigned int nread; - size_t buffer_n; - gcry_error_t err; - - nread = 0; - - while (1) - { - buffer_n = sizeof (buffer); - err = _gcry_ac_io_read (ac_io, nread, buffer, &buffer_n); - if (err) - break; - if (buffer_n) - { - err = (*cb) (opaque, buffer, buffer_n); - if (err) - break; - nread += buffer_n; - } - else - break; - } - - return err; -} - - - -/* - * Functions for converting data between the native ac and the - * S-expression structure used by the pk interface. - */ - -/* 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 [...] - (ALGORITHM <list of named MPI values>)) */ -static gcry_error_t -ac_data_extract (const char *identifier, const char *algorithm, - gcry_sexp_t sexp, gcry_ac_data_t *data) -{ - gcry_error_t err; - gcry_sexp_t value_sexp; - gcry_sexp_t data_sexp; - size_t data_sexp_n; - gcry_mpi_t value_mpi; - char *value_name; - const char *data_raw; - size_t data_raw_n; - gcry_ac_data_t data_new; - unsigned int i; - - value_sexp = NULL; - data_sexp = NULL; - value_name = NULL; - value_mpi = NULL; - data_new = NULL; - - /* Verify that the S-expression contains the correct identifier. */ - data_raw = gcry_sexp_nth_data (sexp, 0, &data_raw_n); - if ((! data_raw) || strncmp (identifier, data_raw, data_raw_n)) - { - err = gcry_error (GPG_ERR_INV_SEXP); - goto out; - } - - /* Extract inner S-expression. */ - data_sexp = gcry_sexp_find_token (sexp, algorithm, 0); - if (! data_sexp) - { - err = gcry_error (GPG_ERR_INV_SEXP); - goto out; - } - - /* Count data elements. */ - data_sexp_n = gcry_sexp_length (data_sexp); - data_sexp_n--; - - /* Allocate new data set. */ - err = _gcry_ac_data_new (&data_new); - if (err) - goto out; - - /* Iterate through list of data elements and add them to the data - set. */ - for (i = 0; i < data_sexp_n; i++) - { - /* Get the S-expression of the named MPI, that contains the name - and the MPI value. */ - value_sexp = gcry_sexp_nth (data_sexp, i + 1); - if (! value_sexp) - { - err = gcry_error (GPG_ERR_INV_SEXP); - break; - } - - /* Extract the name. */ - data_raw = gcry_sexp_nth_data (value_sexp, 0, &data_raw_n); - if (! data_raw) - { - err = gcry_error (GPG_ERR_INV_SEXP); - break; - } - - /* Extract the MPI value. */ - value_mpi = gcry_sexp_nth_mpi (value_sexp, 1, GCRYMPI_FMT_USG); - if (! value_mpi) - { - err = gcry_error (GPG_ERR_INTERNAL); /* FIXME? */ - break; - } - - /* Duplicate the name. */ - value_name = gcry_malloc (data_raw_n + 1); - if (! value_name) - { - err = gcry_error_from_errno (errno); - break; - } - strncpy (value_name, data_raw, data_raw_n); - value_name[data_raw_n] = 0; - - err = _gcry_ac_data_set (data_new, GCRY_AC_FLAG_DEALLOC, value_name, value_mpi); - if (err) - break; - - gcry_sexp_release (value_sexp); - value_sexp = NULL; - value_name = NULL; - value_mpi = NULL; - } - if (err) - goto out; - - /* Copy out. */ - *data = data_new; - - out: - - /* Deallocate resources. */ - if (err) - { - _gcry_ac_data_destroy (data_new); - gcry_mpi_release (value_mpi); - gcry_free (value_name); - gcry_sexp_release (value_sexp); - } - gcry_sexp_release (data_sexp); - - 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_error_t -ac_data_construct (const char *identifier, int include_flags, - unsigned int flags, const char *algorithm, - gcry_ac_data_t data, gcry_sexp_t *sexp) -{ - unsigned int data_length; - gcry_sexp_t sexp_new; - gcry_error_t err; - size_t sexp_format_n; - char *sexp_format; - void **arg_list; - unsigned int i; - - arg_list = NULL; - sexp_new = NULL; - sexp_format = NULL; - - /* We build a list of arguments to pass to - gcry_sexp_build_array(). */ - data_length = _gcry_ac_data_length (data); - arg_list = gcry_malloc (sizeof (*arg_list) * (data_length * 2)); - if (! arg_list) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Fill list with MPIs. */ - for (i = 0; i < data_length; i++) - { - char **nameaddr = &data->data[i].name; - - arg_list[(i * 2) + 0] = nameaddr; - arg_list[(i * 2) + 1] = &data->data[i].mpi; - } - - /* Calculate size of format string. */ - sexp_format_n = (3 - + (include_flags ? 7 : 0) - + (algorithm ? (2 + strlen (algorithm)) : 0) - + strlen (identifier)); - - for (i = 0; i < data_length; i++) - /* Per-element sizes. */ - sexp_format_n += 6; - - if (include_flags) - /* Add flags. */ - for (i = 0; i < DIM (ac_flags); i++) - if (flags & ac_flags[i].number) - sexp_format_n += strlen (ac_flags[i].string) + 1; - - /* Done. */ - sexp_format = gcry_malloc (sexp_format_n); - if (! sexp_format) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Construct the format string. */ - - *sexp_format = 0; - strcat (sexp_format, "("); - strcat (sexp_format, identifier); - if (include_flags) - { - strcat (sexp_format, "(flags"); - for (i = 0; i < DIM (ac_flags); i++) - if (flags & ac_flags[i].number) - { - strcat (sexp_format, " "); - strcat (sexp_format, ac_flags[i].string); - } - strcat (sexp_format, ")"); - } - if (algorithm) - { - strcat (sexp_format, "("); - strcat (sexp_format, algorithm); - } - for (i = 0; i < data_length; i++) - strcat (sexp_format, "(%s%m)"); - if (algorithm) - strcat (sexp_format, ")"); - strcat (sexp_format, ")"); - - /* Create final S-expression. */ - err = gcry_sexp_build_array (&sexp_new, NULL, sexp_format, arg_list); - if (err) - goto out; - - *sexp = sexp_new; - - out: - - /* Deallocate resources. */ - gcry_free (sexp_format); - gcry_free (arg_list); - if (err) - gcry_sexp_release (sexp_new); - - return err; -} - - - -/* - * Handle management. - */ - -/* Creates a new handle for the algorithm ALGORITHM and stores 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_ac_handle_t handle_new; - const char *algorithm_name; - gcry_module_t module; - gcry_error_t err; - - *handle = NULL; - module = NULL; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - /* Get name. */ - algorithm_name = _gcry_pk_aliased_algo_name (algorithm); - if (! algorithm_name) - { - err = gcry_error (GPG_ERR_PUBKEY_ALGO); - goto out; - } - - /* Acquire reference to the pubkey module. */ - err = _gcry_pk_module_lookup (algorithm, &module); - if (err) - goto out; - - /* Allocate. */ - handle_new = gcry_malloc (sizeof (*handle_new)); - if (! handle_new) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Done. */ - handle_new->algorithm = algorithm; - handle_new->algorithm_name = algorithm_name; - handle_new->flags = flags; - handle_new->module = module; - *handle = handle_new; - - out: - - /* Deallocate resources. */ - if (err) - _gcry_pk_module_release (module); - - return 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. - */ - -/* Initialize a key from a given data set. */ -/* FIXME/Damn: the argument HANDLE is not only unnecessary, it is - completely WRONG here. */ -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_ac_data_t data_new; - gcry_ac_key_t key_new; - gcry_error_t err; - - (void)handle; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - /* Allocate. */ - key_new = gcry_malloc (sizeof (*key_new)); - if (! key_new) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Copy data set. */ - err = _gcry_ac_data_copy (&data_new, data); - if (err) - goto out; - - /* Done. */ - key_new->data = data_new; - key_new->type = type; - *key = key_new; - - out: - - if (err) - /* Deallocate resources. */ - gcry_free (key_new); - - return 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_sexp_t genkey_sexp_request; - gcry_sexp_t genkey_sexp_reply; - gcry_ac_data_t key_data_secret; - gcry_ac_data_t key_data_public; - gcry_ac_key_pair_t key_pair_new; - gcry_ac_key_t key_secret; - gcry_ac_key_t key_public; - gcry_sexp_t key_sexp; - gcry_error_t err; - char *genkey_format; - size_t genkey_format_n; - void **arg_list; - size_t arg_list_n; - unsigned int i; - unsigned int j; - - (void)misc_data; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - key_data_secret = NULL; - key_data_public = NULL; - key_secret = NULL; - key_public = NULL; - genkey_format = NULL; - arg_list = NULL; - genkey_sexp_request = NULL; - genkey_sexp_reply = NULL; - key_sexp = NULL; - - /* Allocate key pair. */ - key_pair_new = gcry_malloc (sizeof (struct gcry_ac_key_pair)); - if (! key_pair_new) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Allocate keys. */ - key_secret = gcry_malloc (sizeof (*key_secret)); - if (! key_secret) - { - err = gcry_error_from_errno (errno); - goto out; - } - key_public = gcry_malloc (sizeof (*key_public)); - if (! key_public) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Calculate size of the format string, that is used for creating - the request S-expression. */ - genkey_format_n = 22; - - /* Respect any relevant algorithm specific commands. */ - if (key_spec) - for (i = 0; i < DIM (ac_key_generate_specs); i++) - if (handle->algorithm == ac_key_generate_specs[i].algorithm) - genkey_format_n += 6; - - /* Create format string. */ - genkey_format = gcry_malloc (genkey_format_n); - if (! genkey_format) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Fill format string. */ - *genkey_format = 0; - strcat (genkey_format, "(genkey(%s(nbits%d)"); - if (key_spec) - for (i = 0; i < DIM (ac_key_generate_specs); i++) - if (handle->algorithm == ac_key_generate_specs[i].algorithm) - strcat (genkey_format, "(%s%m)"); - strcat (genkey_format, "))"); - - /* Build list of argument pointers, the algorithm name and the nbits - are always needed. */ - arg_list_n = 2; - - /* Now the algorithm specific arguments. */ - if (key_spec) - for (i = 0; i < DIM (ac_key_generate_specs); i++) - if (handle->algorithm == ac_key_generate_specs[i].algorithm) - arg_list_n += 2; - - /* Allocate list. */ - arg_list = gcry_malloc (sizeof (*arg_list) * arg_list_n); - if (! arg_list) - { - err = gcry_error_from_errno (errno); - goto out; - } - - arg_list[0] = (void *) &handle->algorithm_name; - arg_list[1] = (void *) &nbits; - if (key_spec) - for (j = 2, i = 0; i < DIM (ac_key_generate_specs); i++) - if (handle->algorithm == ac_key_generate_specs[i].algorithm) - { - /* Add name of this specification flag and the - according member of the spec strucuture. */ - arg_list[j++] = (void *)(&ac_key_generate_specs[i].name); - arg_list[j++] = (void *) - (((char *) key_spec) - + ac_key_generate_specs[i].offset); - /* FIXME: above seems to suck. */ - } - - /* Construct final request S-expression. */ - err = gcry_sexp_build_array (&genkey_sexp_request, - NULL, genkey_format, arg_list); - if (err) - goto out; - - /* Perform genkey operation. */ - err = gcry_pk_genkey (&genkey_sexp_reply, genkey_sexp_request); - if (err) - goto out; - - key_sexp = gcry_sexp_find_token (genkey_sexp_reply, "private-key", 0); - if (! key_sexp) - { - err = gcry_error (GPG_ERR_INTERNAL); - goto out; - } - err = ac_data_extract ("private-key", handle->algorithm_name, - key_sexp, &key_data_secret); - if (err) - goto out; - - gcry_sexp_release (key_sexp); - key_sexp = gcry_sexp_find_token (genkey_sexp_reply, "public-key", 0); - if (! key_sexp) - { - err = gcry_error (GPG_ERR_INTERNAL); - goto out; - } - err = ac_data_extract ("public-key", handle->algorithm_name, - key_sexp, &key_data_public); - if (err) - goto out; - - /* Done. */ - - key_secret->type = GCRY_AC_KEY_SECRET; - key_secret->data = key_data_secret; - key_public->type = GCRY_AC_KEY_PUBLIC; - key_public->data = key_data_public; - key_pair_new->secret = key_secret; - key_pair_new->public = key_public; - *key_pair = key_pair_new; - - out: - - /* Deallocate resources. */ - - gcry_free (genkey_format); - gcry_free (arg_list); - gcry_sexp_release (genkey_sexp_request); - gcry_sexp_release (genkey_sexp_reply); - gcry_sexp_release (key_sexp); - if (err) - { - _gcry_ac_data_destroy (key_data_secret); - _gcry_ac_data_destroy (key_data_public); - gcry_free (key_secret); - gcry_free (key_public); - gcry_free (key_pair_new); - } - - return 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 which) -{ - gcry_ac_key_t key; - - if (fips_mode ()) - return NULL; - - switch (which) - { - case GCRY_AC_KEY_SECRET: - key = key_pair->secret; - break; - - case GCRY_AC_KEY_PUBLIC: - key = key_pair->public; - break; - - default: - key = NULL; - break; - } - - return key; -} - -/* Destroys the key KEY. */ -void -_gcry_ac_key_destroy (gcry_ac_key_t key) -{ - unsigned int i; - - if (key) - { - if (key->data) - { - for (i = 0; i < key->data->data_n; i++) - { - if (key->data->data[i].mpi) - gcry_mpi_release (key->data->data[i].mpi); - if (key->data->data[i].name) - gcry_free (key->data->data[i].name); - } - gcry_free (key->data->data); - gcry_free (key->data); - } - 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) -{ - if (fips_mode ()) - return NULL; - 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_sexp_t key_sexp; - gcry_error_t err; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - key_sexp = NULL; - err = ac_data_construct (ac_key_identifiers[key->type], 0, 0, - handle->algorithm_name, key->data, &key_sexp); - if (err) - goto out; - - err = gcry_pk_testkey (key_sexp); - - out: - - gcry_sexp_release (key_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_sexp_t key_sexp; - gcry_error_t err; - unsigned int n; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - key_sexp = NULL; - - err = ac_data_construct (ac_key_identifiers[key->type], - 0, 0, handle->algorithm_name, key->data, &key_sexp); - if (err) - goto out; - - n = gcry_pk_get_nbits (key_sexp); - if (! n) - { - err = gcry_error (GPG_ERR_PUBKEY_ALGO); - goto out; - } - - *nbits = n; - - out: - - gcry_sexp_release (key_sexp); - - return 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_sexp_t key_sexp; - gcry_error_t err; - unsigned char *ret; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - key_sexp = NULL; - err = ac_data_construct (ac_key_identifiers[key->type], 0, 0, - handle->algorithm_name, key->data, &key_sexp); - if (err) - goto out; - - ret = gcry_pk_get_keygrip (key_sexp, key_grip); - if (! ret) - { - err = gcry_error (GPG_ERR_INV_OBJ); - goto out; - } - - err = 0; - - out: - - gcry_sexp_release (key_sexp); - - return 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_ac_data_t data_encrypted_new; - gcry_ac_data_t data_value; - gcry_sexp_t sexp_request; - gcry_sexp_t sexp_reply; - gcry_sexp_t sexp_key; - gcry_error_t err; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - data_encrypted_new = NULL; - sexp_request = NULL; - sexp_reply = NULL; - data_value = NULL; - sexp_key = NULL; - - if (key->type != GCRY_AC_KEY_PUBLIC) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - err = ac_data_construct (ac_key_identifiers[key->type], 0, 0, - handle->algorithm_name, key->data, &sexp_key); - if (err) - goto out; - - err = _gcry_ac_data_new (&data_value); - if (err) - goto out; - - err = _gcry_ac_data_set (data_value, 0, "value", data_plain); - if (err) - goto out; - - err = ac_data_construct ("data", 1, flags, handle->algorithm_name, - data_value, &sexp_request); - if (err) - goto out; - - /* FIXME: error vs. errcode? */ - - err = gcry_pk_encrypt (&sexp_reply, sexp_request, sexp_key); - if (err) - goto out; - - /* Extract data. */ - err = ac_data_extract ("enc-val", handle->algorithm_name, - sexp_reply, &data_encrypted_new); - if (err) - goto out; - - *data_encrypted = data_encrypted_new; - - out: - - /* Deallocate resources. */ - - gcry_sexp_release (sexp_request); - gcry_sexp_release (sexp_reply); - gcry_sexp_release (sexp_key); - _gcry_ac_data_destroy (data_value); - - return 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_mpi_t data_decrypted; - gcry_sexp_t sexp_request; - gcry_sexp_t sexp_reply; - gcry_sexp_t sexp_value; - gcry_sexp_t sexp_key; - gcry_error_t err; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - sexp_request = NULL; - sexp_reply = NULL; - sexp_value = NULL; - sexp_key = NULL; - - if (key->type != GCRY_AC_KEY_SECRET) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - err = ac_data_construct (ac_key_identifiers[key->type], 0, 0, - handle->algorithm_name, key->data, &sexp_key); - if (err) - goto out; - - /* Create S-expression from data. */ - err = ac_data_construct ("enc-val", 1, flags, handle->algorithm_name, - data_encrypted, &sexp_request); - if (err) - goto out; - - /* Decrypt. */ - err = gcry_pk_decrypt (&sexp_reply, sexp_request, sexp_key); - if (err) - goto out; - - /* Extract plain text. */ - sexp_value = gcry_sexp_find_token (sexp_reply, "value", 0); - if (! sexp_value) - { - /* FIXME? */ - err = gcry_error (GPG_ERR_GENERAL); - goto out; - } - - data_decrypted = gcry_sexp_nth_mpi (sexp_value, 1, GCRYMPI_FMT_USG); - if (! data_decrypted) - { - err = gcry_error (GPG_ERR_GENERAL); - goto out; - } - - *data_plain = data_decrypted; - - out: - - /* Deallocate resources. */ - gcry_sexp_release (sexp_request); - gcry_sexp_release (sexp_reply); - gcry_sexp_release (sexp_value); - gcry_sexp_release (sexp_key); - - 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_ac_data_t data_signed; - gcry_ac_data_t data_value; - gcry_sexp_t sexp_request; - gcry_sexp_t sexp_reply; - gcry_sexp_t sexp_key; - gcry_error_t err; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - data_signed = NULL; - data_value = NULL; - sexp_request = NULL; - sexp_reply = NULL; - sexp_key = NULL; - - if (key->type != GCRY_AC_KEY_SECRET) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - err = ac_data_construct (ac_key_identifiers[key->type], 0, 0, - handle->algorithm_name, key->data, &sexp_key); - if (err) - goto out; - - err = _gcry_ac_data_new (&data_value); - if (err) - goto out; - - err = _gcry_ac_data_set (data_value, 0, "value", data); - if (err) - goto out; - - /* Create S-expression holding the data. */ - err = ac_data_construct ("data", 1, 0, NULL, data_value, &sexp_request); - if (err) - goto out; - - /* Sign. */ - err = gcry_pk_sign (&sexp_reply, sexp_request, sexp_key); - if (err) - goto out; - - /* Extract data. */ - err = ac_data_extract ("sig-val", handle->algorithm_name, - sexp_reply, &data_signed); - if (err) - goto out; - - /* Done. */ - *data_signature = data_signed; - - out: - - gcry_sexp_release (sexp_request); - gcry_sexp_release (sexp_reply); - gcry_sexp_release (sexp_key); - _gcry_ac_data_destroy (data_value); - - 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_sexp_t sexp_signature; - gcry_ac_data_t data_value; - gcry_sexp_t sexp_data; - gcry_sexp_t sexp_key; - gcry_error_t err; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - sexp_signature = NULL; - data_value = NULL; - sexp_data = NULL; - sexp_key = NULL; - - err = ac_data_construct ("public-key", 0, 0, - handle->algorithm_name, key->data, &sexp_key); - if (err) - goto out; - - if (key->type != GCRY_AC_KEY_PUBLIC) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - /* Construct S-expression holding the signature data. */ - err = ac_data_construct ("sig-val", 1, 0, handle->algorithm_name, - data_signature, &sexp_signature); - if (err) - goto out; - - err = _gcry_ac_data_new (&data_value); - if (err) - goto out; - - err = _gcry_ac_data_set (data_value, 0, "value", data); - if (err) - goto out; - - /* Construct S-expression holding the data. */ - err = ac_data_construct ("data", 1, 0, NULL, data_value, &sexp_data); - if (err) - goto out; - - /* Verify signature. */ - err = gcry_pk_verify (sexp_signature, sexp_data, sexp_key); - - out: - - gcry_sexp_release (sexp_signature); - gcry_sexp_release (sexp_data); - gcry_sexp_release (sexp_key); - _gcry_ac_data_destroy (data_value); - - return gcry_error (err); -} - - - - -/* - * Implementation of encoding methods (em). - */ - -/* Type for functions that encode or decode (hence the name) a - message. */ -typedef gcry_error_t (*gcry_ac_em_dencode_t) (unsigned int flags, - void *options, - gcry_ac_io_t *ac_io_read, - gcry_ac_io_t *ac_io_write); - -/* Fill the buffer BUFFER which is BUFFER_N bytes long with non-zero - random bytes of random level LEVEL. */ -static void -em_randomize_nonzero (unsigned char *buffer, size_t buffer_n, - gcry_random_level_t level) -{ - unsigned char *buffer_rand; - unsigned int buffer_rand_n; - unsigned int zeros; - unsigned int i; - unsigned int j; - - for (i = 0; i < buffer_n; i++) - buffer[i] = 0; - - do - { - /* Count zeros. */ - for (i = zeros = 0; i < buffer_n; i++) - if (! buffer[i]) - zeros++; - - if (zeros) - { - /* Get random bytes. */ - buffer_rand_n = zeros + (zeros / 128); - buffer_rand = gcry_random_bytes_secure (buffer_rand_n, level); - - /* Substitute zeros with non-zero random bytes. */ - for (i = j = 0; zeros && (i < buffer_n) && (j < buffer_rand_n); i++) - if (! buffer[i]) - { - while ((j < buffer_rand_n) && (! buffer_rand[j])) - j++; - if (j < buffer_rand_n) - { - buffer[i] = buffer_rand[j++]; - zeros--; - } - else - break; - } - gcry_free (buffer_rand); - } - } - while (zeros); -} - -/* Encode a message according to the Encoding Method for Encryption - `PKCS-V1_5' (EME-PKCS-V1_5). */ -static gcry_error_t -eme_pkcs_v1_5_encode (unsigned int flags, void *opts, - gcry_ac_io_t *ac_io_read, - gcry_ac_io_t *ac_io_write) -{ - gcry_ac_eme_pkcs_v1_5_t *options; - gcry_error_t err; - unsigned char *buffer; - unsigned char *ps; - unsigned char *m; - size_t m_n; - unsigned int ps_n; - unsigned int k; - - (void)flags; - - options = opts; - buffer = NULL; - m = NULL; - - err = _gcry_ac_io_read_all (ac_io_read, &m, &m_n); - if (err) - goto out; - - /* Figure out key length in bytes. */ - k = options->key_size / 8; - - if (m_n > k - 11) - { - /* Key is too short for message. */ - err = gcry_error (GPG_ERR_TOO_SHORT); - goto out; - } - - /* According to this encoding method, the first byte of the encoded - message is zero. This byte will be lost anyway, when the encoded - message is to be converted into an MPI, that's why we skip - it. */ - - /* Allocate buffer. */ - buffer = gcry_malloc (k - 1); - if (! buffer) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Generate an octet string PS of length k - mLen - 3 consisting - of pseudorandomly generated nonzero octets. The length of PS - will be at least eight octets. */ - ps_n = k - m_n - 3; - ps = buffer + 1; - em_randomize_nonzero (ps, ps_n, GCRY_STRONG_RANDOM); - - /* Concatenate PS, the message M, and other padding to form an - encoded message EM of length k octets as: - - EM = 0x00 || 0x02 || PS || 0x00 || M. */ - - buffer[0] = 0x02; - buffer[ps_n + 1] = 0x00; - memcpy (buffer + ps_n + 2, m, m_n); - - err = _gcry_ac_io_write (ac_io_write, buffer, k - 1); - - out: - - gcry_free (buffer); - gcry_free (m); - - return err; -} - -/* Decode a message according to the Encoding Method for Encryption - `PKCS-V1_5' (EME-PKCS-V1_5). */ -static gcry_error_t -eme_pkcs_v1_5_decode (unsigned int flags, void *opts, - gcry_ac_io_t *ac_io_read, - gcry_ac_io_t *ac_io_write) -{ - gcry_ac_eme_pkcs_v1_5_t *options; - unsigned char *buffer; - unsigned char *em; - size_t em_n; - gcry_error_t err; - unsigned int i; - unsigned int k; - - (void)flags; - - options = opts; - buffer = NULL; - em = NULL; - - err = _gcry_ac_io_read_all (ac_io_read, &em, &em_n); - if (err) - goto out; - - /* Figure out key size. */ - k = options->key_size / 8; - - /* Search for zero byte. */ - for (i = 0; (i < em_n) && em[i]; i++); - - /* According to this encoding method, the first byte of the encoded - message should be zero. This byte is lost. */ - - if (! ((em_n >= 10) - && (em_n == (k - 1)) - && (em[0] == 0x02) - && (i < em_n) - && ((i - 1) >= 8))) - { - err = gcry_error (GPG_ERR_DECRYPT_FAILED); - goto out; - } - - i++; - buffer = gcry_malloc (em_n - i); - if (! buffer) - { - err = gcry_error_from_errno (errno); - goto out; - } - - memcpy (buffer, em + i, em_n - i); - err = _gcry_ac_io_write (ac_io_write, buffer, em_n - i); - - out: - - gcry_free (buffer); - gcry_free (em); - - return err; -} - -static gcry_error_t -emsa_pkcs_v1_5_encode_data_cb (void *opaque, - unsigned char *buffer, size_t buffer_n) -{ - gcry_md_hd_t md_handle; - - md_handle = opaque; - gcry_md_write (md_handle, buffer, buffer_n); - - return 0; -} - - -/* Encode a message according to the Encoding Method for Signatures - with Appendix `PKCS-V1_5' (EMSA-PKCS-V1_5). */ -static gcry_error_t -emsa_pkcs_v1_5_encode (unsigned int flags, void *opts, - gcry_ac_io_t *ac_io_read, - gcry_ac_io_t *ac_io_write) -{ - gcry_ac_emsa_pkcs_v1_5_t *options; - gcry_error_t err; - gcry_md_hd_t md; - unsigned char *t; - size_t t_n; - unsigned char *h; - size_t h_n; - unsigned char *ps; - size_t ps_n; - unsigned char *buffer; - size_t buffer_n; - unsigned char asn[100]; /* FIXME, always enough? */ - size_t asn_n; - unsigned int i; - - (void)flags; - - options = opts; - buffer = NULL; - md = NULL; - ps = NULL; - t = NULL; - - /* Create hashing handle and get the necessary information. */ - err = gcry_md_open (&md, options->md, 0); - if (err) - goto out; - - asn_n = DIM (asn); - err = gcry_md_algo_info (options->md, GCRYCTL_GET_ASNOID, asn, &asn_n); - if (err) - goto out; - - h_n = gcry_md_get_algo_dlen (options->md); - - err = _gcry_ac_io_process (ac_io_read, emsa_pkcs_v1_5_encode_data_cb, md); - if (err) - goto out; - - h = gcry_md_read (md, 0); - - /* Encode the algorithm ID for the hash function and the hash value - into an ASN.1 value of type DigestInfo with the Distinguished - Encoding Rules (DER), where the type DigestInfo has the syntax: - - DigestInfo ::== SEQUENCE { - digestAlgorithm AlgorithmIdentifier, - digest OCTET STRING - } - - The first field identifies the hash function and the second - contains the hash value. Let T be the DER encoding of the - DigestInfo value and let tLen be the length in octets of T. */ - - t_n = asn_n + h_n; - t = gcry_malloc (t_n); - if (! t) - { - err = gcry_error_from_errno (errno); - goto out; - } - - for (i = 0; i < asn_n; i++) - t[i] = asn[i]; - for (i = 0; i < h_n; i++) - t[asn_n + i] = h[i]; - - /* If emLen < tLen + 11, output "intended encoded message length - too short" and stop. */ - if (options->em_n < t_n + 11) - { - err = gcry_error (GPG_ERR_TOO_SHORT); - goto out; - } - - /* Generate an octet string PS consisting of emLen - tLen - 3 octets - with hexadecimal value 0xFF. The length of PS will be at least 8 - octets. */ - ps_n = options->em_n - t_n - 3; - ps = gcry_malloc (ps_n); - if (! ps) - { - err = gcry_error_from_errno (errno); - goto out; - } - for (i = 0; i < ps_n; i++) - ps[i] = 0xFF; - - /* Concatenate PS, the DER encoding T, and other padding to form the - encoded message EM as: - - EM = 0x00 || 0x01 || PS || 0x00 || T. */ - - buffer_n = ps_n + t_n + 3; - buffer = gcry_malloc (buffer_n); - if (! buffer) - { - err = gcry_error_from_errno (errno); - goto out; - } - - buffer[0] = 0x00; - buffer[1] = 0x01; - for (i = 0; i < ps_n; i++) - buffer[2 + i] = ps[i]; - buffer[2 + ps_n] = 0x00; - for (i = 0; i < t_n; i++) - buffer[3 + ps_n + i] = t[i]; - - err = _gcry_ac_io_write (ac_io_write, buffer, buffer_n); - - out: - - gcry_md_close (md); - - gcry_free (buffer); - gcry_free (ps); - gcry_free (t); - - return err; -} - -/* `Actions' for data_dencode(). */ -typedef enum dencode_action - { - DATA_ENCODE, - DATA_DECODE, - } -dencode_action_t; - -/* Encode or decode a message according to the the encoding method - METHOD; ACTION specifies wether the message that is contained in - BUFFER_IN and of length BUFFER_IN_N should be encoded or decoded. - The resulting message will be stored in a newly allocated buffer in - BUFFER_OUT and BUFFER_OUT_N. */ -static gcry_error_t -ac_data_dencode (gcry_ac_em_t method, dencode_action_t action, - unsigned int flags, void *options, - gcry_ac_io_t *ac_io_read, - gcry_ac_io_t *ac_io_write) -{ - struct - { - gcry_ac_em_t method; - gcry_ac_em_dencode_t encode; - gcry_ac_em_dencode_t decode; - } methods[] = - { - { GCRY_AC_EME_PKCS_V1_5, - eme_pkcs_v1_5_encode, eme_pkcs_v1_5_decode }, - { GCRY_AC_EMSA_PKCS_V1_5, - emsa_pkcs_v1_5_encode, NULL }, - }; - size_t methods_n; - gcry_error_t err; - unsigned int i; - - methods_n = sizeof (methods) / sizeof (*methods); - - for (i = 0; i < methods_n; i++) - if (methods[i].method == method) - break; - if (i == methods_n) - { - err = gcry_error (GPG_ERR_NOT_FOUND); /* FIXME? */ - goto out; - } - - err = 0; - switch (action) - { - case DATA_ENCODE: - if (methods[i].encode) - /* FIXME? */ - err = (*methods[i].encode) (flags, options, ac_io_read, ac_io_write); - break; - - case DATA_DECODE: - if (methods[i].decode) - /* FIXME? */ - err = (*methods[i].decode) (flags, options, ac_io_read, ac_io_write); - break; - - default: - err = gcry_error (GPG_ERR_INV_ARG); - break; - } - - out: - - return err; -} - -/* Encode a message according to the encoding method METHOD. OPTIONS - must be a pointer to a method-specific structure - (gcry_ac_em*_t). */ -gcry_error_t -_gcry_ac_data_encode (gcry_ac_em_t method, - unsigned int flags, void *options, - gcry_ac_io_t *ac_io_read, - gcry_ac_io_t *ac_io_write) -{ - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - return ac_data_dencode (method, DATA_ENCODE, flags, options, - ac_io_read, ac_io_write); -} - -/* Dencode a message according to the encoding method METHOD. OPTIONS - must be a pointer to a method-specific structure - (gcry_ac_em*_t). */ -gcry_error_t -_gcry_ac_data_decode (gcry_ac_em_t method, - unsigned int flags, void *options, - gcry_ac_io_t *ac_io_read, - gcry_ac_io_t *ac_io_write) -{ - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - return ac_data_dencode (method, DATA_DECODE, flags, options, - ac_io_read, ac_io_write); -} - -/* Convert an MPI into an octet string. */ -void -_gcry_ac_mpi_to_os (gcry_mpi_t mpi, unsigned char *os, size_t os_n) -{ - unsigned long digit; - gcry_mpi_t base; - unsigned int i; - unsigned int n; - gcry_mpi_t m; - gcry_mpi_t d; - - if (fips_mode ()) - return; - - base = gcry_mpi_new (0); - gcry_mpi_set_ui (base, 256); - - n = 0; - m = gcry_mpi_copy (mpi); - while (gcry_mpi_cmp_ui (m, 0)) - { - n++; - gcry_mpi_div (m, NULL, m, base, 0); - } - - gcry_mpi_set (m, mpi); - d = gcry_mpi_new (0); - for (i = 0; (i < n) && (i < os_n); i++) - { - gcry_mpi_mod (d, m, base); - _gcry_mpi_get_ui (d, &digit); - gcry_mpi_div (m, NULL, m, base, 0); - os[os_n - i - 1] = (digit & 0xFF); - } - - for (; i < os_n; i++) - os[os_n - i - 1] = 0; - - gcry_mpi_release (base); - gcry_mpi_release (d); - gcry_mpi_release (m); -} - -/* Convert an MPI into an newly allocated octet string. */ -gcry_error_t -_gcry_ac_mpi_to_os_alloc (gcry_mpi_t mpi, unsigned char **os, size_t *os_n) -{ - unsigned char *buffer; - size_t buffer_n; - gcry_error_t err; - unsigned int nbits; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - nbits = gcry_mpi_get_nbits (mpi); - buffer_n = (nbits + 7) / 8; - buffer = gcry_malloc (buffer_n); - if (! buffer) - { - err = gcry_error_from_errno (errno); - goto out; - } - - _gcry_ac_mpi_to_os (mpi, buffer, buffer_n); - *os = buffer; - *os_n = buffer_n; - err = 0; - - out: - - return err; -} - - -/* Convert an octet string into an MPI. */ -void -_gcry_ac_os_to_mpi (gcry_mpi_t mpi, unsigned char *os, size_t os_n) -{ - unsigned int i; - gcry_mpi_t xi; - gcry_mpi_t x; - gcry_mpi_t a; - - if (fips_mode ()) - return; - - a = gcry_mpi_new (0); - gcry_mpi_set_ui (a, 1); - x = gcry_mpi_new (0); - gcry_mpi_set_ui (x, 0); - xi = gcry_mpi_new (0); - - for (i = 0; i < os_n; i++) - { - gcry_mpi_mul_ui (xi, a, os[os_n - i - 1]); - gcry_mpi_add (x, x, xi); - gcry_mpi_mul_ui (a, a, 256); - } - - gcry_mpi_release (xi); - gcry_mpi_release (a); - - gcry_mpi_set (mpi, x); - gcry_mpi_release (x); /* FIXME: correct? */ -} - - - -/* - * Implementation of Encryption Schemes (ES) and Signature Schemes - * with Appendix (SSA). - */ - -/* Schemes consist of two things: encoding methods and cryptographic - primitives. - - Since encoding methods are accessible through a common API with - method-specific options passed as an anonymous struct, schemes have - to provide functions that construct this method-specific structure; - this is what the functions of type `gcry_ac_dencode_prepare_t' are - there for. */ - -typedef gcry_error_t (*gcry_ac_dencode_prepare_t) (gcry_ac_handle_t handle, - gcry_ac_key_t key, - void *opts, - void *opts_em); - -/* The `dencode_prepare' function for ES-PKCS-V1_5. */ -static gcry_error_t -ac_es_dencode_prepare_pkcs_v1_5 (gcry_ac_handle_t handle, gcry_ac_key_t key, - void *opts, void *opts_em) -{ - gcry_ac_eme_pkcs_v1_5_t *options_em; - unsigned int nbits; - gcry_error_t err; - - (void)opts; - - err = _gcry_ac_key_get_nbits (handle, key, &nbits); - if (err) - goto out; - - options_em = opts_em; - options_em->key_size = nbits; - - out: - - return err; -} - -/* The `dencode_prepare' function for SSA-PKCS-V1_5. */ -static gcry_error_t -ac_ssa_dencode_prepare_pkcs_v1_5 (gcry_ac_handle_t handle, gcry_ac_key_t key, - void *opts, void *opts_em) -{ - gcry_ac_emsa_pkcs_v1_5_t *options_em; - gcry_ac_ssa_pkcs_v1_5_t *options; - gcry_error_t err; - unsigned int k; - - options_em = opts_em; - options = opts; - - err = _gcry_ac_key_get_nbits (handle, key, &k); - if (err) - goto out; - - k = (k + 7) / 8; - options_em->md = options->md; - options_em->em_n = k; - - out: - - return err; -} - -/* Type holding the information about each supported - Encryption/Signature Scheme. */ -typedef struct ac_scheme -{ - gcry_ac_scheme_t scheme; - gcry_ac_em_t scheme_encoding; - gcry_ac_dencode_prepare_t dencode_prepare; - size_t options_em_n; -} ac_scheme_t; - -/* List of supported Schemes. */ -static ac_scheme_t ac_schemes[] = - { - { GCRY_AC_ES_PKCS_V1_5, GCRY_AC_EME_PKCS_V1_5, - ac_es_dencode_prepare_pkcs_v1_5, - sizeof (gcry_ac_eme_pkcs_v1_5_t) }, - { GCRY_AC_SSA_PKCS_V1_5, GCRY_AC_EMSA_PKCS_V1_5, - ac_ssa_dencode_prepare_pkcs_v1_5, - sizeof (gcry_ac_emsa_pkcs_v1_5_t) } - }; - -/* Lookup a scheme by it's ID. */ -static ac_scheme_t * -ac_scheme_get (gcry_ac_scheme_t scheme) -{ - ac_scheme_t *ac_scheme; - unsigned int i; - - for (i = 0; i < DIM (ac_schemes); i++) - if (scheme == ac_schemes[i].scheme) - break; - if (i == DIM (ac_schemes)) - ac_scheme = NULL; - else - ac_scheme = ac_schemes + i; - - return ac_scheme; -} - -/* Prepares the encoding/decoding by creating an according option - structure. */ -static gcry_error_t -ac_dencode_prepare (gcry_ac_handle_t handle, gcry_ac_key_t key, void *opts, - ac_scheme_t scheme, void **opts_em) -{ - gcry_error_t err; - void *options_em; - - options_em = gcry_malloc (scheme.options_em_n); - if (! options_em) - { - err = gcry_error_from_errno (errno); - goto out; - } - - err = (*scheme.dencode_prepare) (handle, key, opts, options_em); - if (err) - goto out; - - *opts_em = options_em; - - out: - - if (err) - free (options_em); - - return err; -} - -/* Convert a data set into a single MPI; currently, this is only - supported for data sets containing a single MPI. */ -static gcry_error_t -ac_data_set_to_mpi (gcry_ac_data_t data, gcry_mpi_t *mpi) -{ - gcry_error_t err; - gcry_mpi_t mpi_new; - unsigned int elems; - - elems = _gcry_ac_data_length (data); - - if (elems != 1) - { - /* FIXME: I guess, we should be more flexible in this respect by - allowing the actual encryption/signature schemes to implement - this conversion mechanism. */ - err = gcry_error (GPG_ERR_CONFLICT); - goto out; - } - - err = _gcry_ac_data_get_index (data, GCRY_AC_FLAG_COPY, 0, NULL, &mpi_new); - if (err) - goto out; - - *mpi = mpi_new; - - out: - - return err; -} - -/* Encrypts the plain text message contained in M, which is of size - M_N, with the public key KEY_PUBLIC according to the Encryption - Scheme SCHEME_ID. HANDLE is used for accessing the low-level - cryptographic primitives. If OPTS is not NULL, it has to be an - anonymous structure specific to the chosen scheme (gcry_ac_es_*_t). - The encrypted message will be stored in C and C_N. */ -gcry_error_t -_gcry_ac_data_encrypt_scheme (gcry_ac_handle_t handle, - gcry_ac_scheme_t scheme_id, - unsigned int flags, void *opts, - gcry_ac_key_t key, - gcry_ac_io_t *io_message, - gcry_ac_io_t *io_cipher) -{ - gcry_error_t err; - gcry_ac_io_t io_em; - unsigned char *em; - size_t em_n; - gcry_mpi_t mpi_plain; - gcry_ac_data_t data_encrypted; - gcry_mpi_t mpi_encrypted; - unsigned char *buffer; - size_t buffer_n; - void *opts_em; - ac_scheme_t *scheme; - - (void)flags; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - data_encrypted = NULL; - mpi_encrypted = NULL; - mpi_plain = NULL; - opts_em = NULL; - buffer = NULL; - em = NULL; - - scheme = ac_scheme_get (scheme_id); - if (! scheme) - { - err = gcry_error (GPG_ERR_NO_ENCRYPTION_SCHEME); - goto out; - } - - if (key->type != GCRY_AC_KEY_PUBLIC) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - err = ac_dencode_prepare (handle, key, opts, *scheme, &opts_em); - if (err) - goto out; - - _gcry_ac_io_init (&io_em, GCRY_AC_IO_WRITABLE, - GCRY_AC_IO_STRING, &em, &em_n); - - err = _gcry_ac_data_encode (scheme->scheme_encoding, 0, opts_em, - io_message, &io_em); - if (err) - goto out; - - mpi_plain = gcry_mpi_snew (0); - gcry_ac_os_to_mpi (mpi_plain, em, em_n); - - err = _gcry_ac_data_encrypt (handle, 0, key, mpi_plain, &data_encrypted); - if (err) - goto out; - - err = ac_data_set_to_mpi (data_encrypted, &mpi_encrypted); - if (err) - goto out; - - err = _gcry_ac_mpi_to_os_alloc (mpi_encrypted, &buffer, &buffer_n); - if (err) - goto out; - - err = _gcry_ac_io_write (io_cipher, buffer, buffer_n); - - out: - - gcry_ac_data_destroy (data_encrypted); - gcry_mpi_release (mpi_encrypted); - gcry_mpi_release (mpi_plain); - gcry_free (opts_em); - gcry_free (buffer); - gcry_free (em); - - return err; -} - -/* Decryptes the cipher message contained in C, which is of size C_N, - with the secret key KEY_SECRET according to the Encryption Scheme - SCHEME_ID. Handle is used for accessing the low-level - cryptographic primitives. If OPTS is not NULL, it has to be an - anonymous structure specific to the chosen scheme (gcry_ac_es_*_t). - The decrypted message will be stored in M and M_N. */ -gcry_error_t -_gcry_ac_data_decrypt_scheme (gcry_ac_handle_t handle, - gcry_ac_scheme_t scheme_id, - unsigned int flags, void *opts, - gcry_ac_key_t key, - gcry_ac_io_t *io_cipher, - gcry_ac_io_t *io_message) -{ - gcry_ac_io_t io_em; - gcry_error_t err; - gcry_ac_data_t data_encrypted; - unsigned char *em; - size_t em_n; - gcry_mpi_t mpi_encrypted; - gcry_mpi_t mpi_decrypted; - void *opts_em; - ac_scheme_t *scheme; - char *elements_enc; - size_t elements_enc_n; - unsigned char *c; - size_t c_n; - - (void)flags; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - data_encrypted = NULL; - mpi_encrypted = NULL; - mpi_decrypted = NULL; - elements_enc = NULL; - opts_em = NULL; - em = NULL; - c = NULL; - - scheme = ac_scheme_get (scheme_id); - if (! scheme) - { - err = gcry_error (GPG_ERR_NO_ENCRYPTION_SCHEME); - goto out; - } - - if (key->type != GCRY_AC_KEY_SECRET) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - err = _gcry_ac_io_read_all (io_cipher, &c, &c_n); - if (err) - goto out; - - mpi_encrypted = gcry_mpi_snew (0); - gcry_ac_os_to_mpi (mpi_encrypted, c, c_n); - - err = _gcry_pk_get_elements (handle->algorithm, &elements_enc, NULL); - if (err) - goto out; - - elements_enc_n = strlen (elements_enc); - if (elements_enc_n != 1) - { - /* FIXME? */ - err = gcry_error (GPG_ERR_CONFLICT); - goto out; - } - - err = _gcry_ac_data_new (&data_encrypted); - if (err) - goto out; - - err = _gcry_ac_data_set (data_encrypted, GCRY_AC_FLAG_COPY | GCRY_AC_FLAG_DEALLOC, - elements_enc, mpi_encrypted); - if (err) - goto out; - - err = _gcry_ac_data_decrypt (handle, 0, key, &mpi_decrypted, data_encrypted); - if (err) - goto out; - - err = _gcry_ac_mpi_to_os_alloc (mpi_decrypted, &em, &em_n); - if (err) - goto out; - - err = ac_dencode_prepare (handle, key, opts, *scheme, &opts_em); - if (err) - goto out; - - _gcry_ac_io_init (&io_em, GCRY_AC_IO_READABLE, - GCRY_AC_IO_STRING, em, em_n); - - err = _gcry_ac_data_decode (scheme->scheme_encoding, 0, opts_em, - &io_em, io_message); - if (err) - goto out; - - out: - - _gcry_ac_data_destroy (data_encrypted); - gcry_mpi_release (mpi_encrypted); - gcry_mpi_release (mpi_decrypted); - free (elements_enc); - gcry_free (opts_em); - gcry_free (em); - gcry_free (c); - - return err; -} - - -/* Signs the message contained in M, which is of size M_N, with the - secret key KEY according to the Signature Scheme SCHEME_ID. Handle - is used for accessing the low-level cryptographic primitives. If - OPTS is not NULL, it has to be an anonymous structure specific to - the chosen scheme (gcry_ac_ssa_*_t). The signed message will be - stored in S and S_N. */ -gcry_error_t -_gcry_ac_data_sign_scheme (gcry_ac_handle_t handle, - gcry_ac_scheme_t scheme_id, - unsigned int flags, void *opts, - gcry_ac_key_t key, - gcry_ac_io_t *io_message, - gcry_ac_io_t *io_signature) -{ - gcry_ac_io_t io_em; - gcry_error_t err; - gcry_ac_data_t data_signed; - unsigned char *em; - size_t em_n; - gcry_mpi_t mpi; - void *opts_em; - unsigned char *buffer; - size_t buffer_n; - gcry_mpi_t mpi_signed; - ac_scheme_t *scheme; - - (void)flags; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - data_signed = NULL; - mpi_signed = NULL; - opts_em = NULL; - buffer = NULL; - mpi = NULL; - em = NULL; - - if (key->type != GCRY_AC_KEY_SECRET) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - scheme = ac_scheme_get (scheme_id); - if (! scheme) - { - /* FIXME: adjust api of scheme_get in respect to err codes. */ - err = gcry_error (GPG_ERR_NO_SIGNATURE_SCHEME); - goto out; - } - - err = ac_dencode_prepare (handle, key, opts, *scheme, &opts_em); - if (err) - goto out; - - _gcry_ac_io_init (&io_em, GCRY_AC_IO_WRITABLE, - GCRY_AC_IO_STRING, &em, &em_n); - - err = _gcry_ac_data_encode (scheme->scheme_encoding, 0, opts_em, - io_message, &io_em); - if (err) - goto out; - - mpi = gcry_mpi_new (0); - _gcry_ac_os_to_mpi (mpi, em, em_n); - - err = _gcry_ac_data_sign (handle, key, mpi, &data_signed); - if (err) - goto out; - - err = ac_data_set_to_mpi (data_signed, &mpi_signed); - if (err) - goto out; - - err = _gcry_ac_mpi_to_os_alloc (mpi_signed, &buffer, &buffer_n); - if (err) - goto out; - - err = _gcry_ac_io_write (io_signature, buffer, buffer_n); - - out: - - _gcry_ac_data_destroy (data_signed); - gcry_mpi_release (mpi_signed); - gcry_mpi_release (mpi); - gcry_free (opts_em); - gcry_free (buffer); - gcry_free (em); - - return err; -} - -/* Verifies that the signature contained in S, which is of length S_N, - is indeed the result of signing the message contained in M, which - is of size M_N, with the secret key belonging to the public key - KEY_PUBLIC. If OPTS is not NULL, it has to be an anonymous - structure (gcry_ac_ssa_*_t) specific to the Signature Scheme, whose - ID is contained in SCHEME_ID. */ -gcry_error_t -_gcry_ac_data_verify_scheme (gcry_ac_handle_t handle, - gcry_ac_scheme_t scheme_id, - unsigned int flags, void *opts, - gcry_ac_key_t key, - gcry_ac_io_t *io_message, - gcry_ac_io_t *io_signature) -{ - gcry_ac_io_t io_em; - gcry_error_t err; - gcry_ac_data_t data_signed; - unsigned char *em; - size_t em_n; - void *opts_em; - gcry_mpi_t mpi_signature; - gcry_mpi_t mpi_data; - ac_scheme_t *scheme; - char *elements_sig; - size_t elements_sig_n; - unsigned char *s; - size_t s_n; - - (void)flags; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - mpi_signature = NULL; - elements_sig = NULL; - data_signed = NULL; - mpi_data = NULL; - opts_em = NULL; - em = NULL; - s = NULL; - - if (key->type != GCRY_AC_KEY_PUBLIC) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - scheme = ac_scheme_get (scheme_id); - if (! scheme) - { - err = gcry_error (GPG_ERR_NO_SIGNATURE_SCHEME); - goto out; - } - - err = ac_dencode_prepare (handle, key, opts, *scheme, &opts_em); - if (err) - goto out; - - _gcry_ac_io_init (&io_em, GCRY_AC_IO_WRITABLE, - GCRY_AC_IO_STRING, &em, &em_n); - - err = _gcry_ac_data_encode (scheme->scheme_encoding, 0, opts_em, - io_message, &io_em); - if (err) - goto out; - - mpi_data = gcry_mpi_new (0); - _gcry_ac_os_to_mpi (mpi_data, em, em_n); - - err = _gcry_ac_io_read_all (io_signature, &s, &s_n); - if (err) - goto out; - - mpi_signature = gcry_mpi_new (0); - _gcry_ac_os_to_mpi (mpi_signature, s, s_n); - - err = _gcry_pk_get_elements (handle->algorithm, NULL, &elements_sig); - if (err) - goto out; - - elements_sig_n = strlen (elements_sig); - if (elements_sig_n != 1) - { - /* FIXME? */ - err = gcry_error (GPG_ERR_CONFLICT); - goto out; - } - - err = _gcry_ac_data_new (&data_signed); - if (err) - goto out; - - err = _gcry_ac_data_set (data_signed, GCRY_AC_FLAG_COPY | GCRY_AC_FLAG_DEALLOC, - elements_sig, mpi_signature); - if (err) - goto out; - - gcry_mpi_release (mpi_signature); - mpi_signature = NULL; - - err = _gcry_ac_data_verify (handle, key, mpi_data, data_signed); - - out: - - _gcry_ac_data_destroy (data_signed); - gcry_mpi_release (mpi_signature); - gcry_mpi_release (mpi_data); - free (elements_sig); - gcry_free (opts_em); - gcry_free (em); - gcry_free (s); - - return err; -} - - -/* - * General functions. - */ - -gcry_err_code_t -_gcry_ac_init (void) -{ - if (fips_mode ()) - return GPG_ERR_NOT_SUPPORTED; - - return 0; -} |