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