2009-11-16 20:59:10 +00:00
|
|
|
|
/* ac.c - Alternative interface for asymmetric cryptography.
|
|
|
|
|
Copyright (C) 2003, 2004, 2005, 2006
|
|
|
|
|
2007, 2008 Free Software Foundation, Inc.
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
This file is part of Libgcrypt.
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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.
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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.
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-11-07 05:35:50 +00:00
|
|
|
|
/*
|
2009-11-16 20:59:10 +00:00
|
|
|
|
* 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;
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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;
|
|
|
|
|
|
2020-06-15 16:26:01 +00:00
|
|
|
|
data_mpis_new = gcry_calloc (data_mpis_n, sizeof (*data_mpis_new));
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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;
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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;
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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;
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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. */
|
2020-06-15 16:26:01 +00:00
|
|
|
|
arg_list = gcry_calloc (data_n + 1, sizeof (*arg_list));
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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:
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
(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. */
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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);
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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;
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-11-07 05:35:50 +00:00
|
|
|
|
/*
|
2009-11-16 20:59:10 +00:00
|
|
|
|
* 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);
|
2020-06-15 16:26:01 +00:00
|
|
|
|
arg_list = gcry_calloc (data_length, sizeof (*arg_list) * 2);
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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;
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
/* 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:
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-11-07 05:35:50 +00:00
|
|
|
|
/*
|
2009-11-16 20:59:10 +00:00
|
|
|
|
* 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. */
|
2020-06-15 16:26:01 +00:00
|
|
|
|
arg_list = gcry_calloc (arg_list_n, sizeof (*arg_list));
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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. */
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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
|
2013-11-07 05:35:50 +00:00
|
|
|
|
_gcry_ac_key_pair_extract (gcry_ac_key_pair_t key_pair,
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-11-07 05:35:50 +00:00
|
|
|
|
/*
|
2009-11-16 20:59:10 +00:00
|
|
|
|
* 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;
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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;
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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
|
2013-01-11 20:32:42 +00:00
|
|
|
|
METHOD; ACTION specifies whether the message that is contained in
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
_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;
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
gcry_mpi_release (xi);
|
|
|
|
|
gcry_mpi_release (a);
|
|
|
|
|
|
|
|
|
|
gcry_mpi_set (mpi, x);
|
|
|
|
|
gcry_mpi_release (x); /* FIXME: correct? */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-11-07 05:35:50 +00:00
|
|
|
|
/*
|
2009-11-16 20:59:10 +00:00
|
|
|
|
* 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;
|
|
|
|
|
}
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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:
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
_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;
|
2013-11-07 05:35:50 +00:00
|
|
|
|
|
2009-11-16 20:59:10 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-11-07 05:35:50 +00:00
|
|
|
|
/*
|
2009-11-16 20:59:10 +00:00
|
|
|
|
* General functions.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
gcry_err_code_t
|
|
|
|
|
_gcry_ac_init (void)
|
|
|
|
|
{
|
|
|
|
|
if (fips_mode ())
|
|
|
|
|
return GPG_ERR_NOT_SUPPORTED;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|