Editorial changes and allow building with old libgcrypts.

Changed order of some conditional to make to put the special case into
the true branch.  Indentation changes.  Minor other changes to make the
ECC code more similar to the rest of our code.

It builds but many sefltests still fail.  Need to fix that before
using it with an ECDH enabled libgcrypt.

[/]
2011-01-21  Werner Koch  <wk@g10code.com>

	* configure.ac: Need Libgcrypt 1.4.6 due to AESWRAP.
	(HAVE_GCRY_PK_ECDH): Add new test.

[agent/]
2011-01-21  Werner Koch  <wk@g10code.com>

	* cvt-openpgp.c (GCRY_PK_ECDH) [!HAVE_GCRY_PK_ECDH]: New.

[include/]
2011-01-21  Werner Koch  <wk@g10code.com>

	* cipher.h (GCRY_PK_USAGE_CERT): Remove compatibility macros
	because we now require libgcrypt 1.4.6.
	(GCRY_PK_ECDH): Add replacement.
This commit is contained in:
Werner Koch 2011-01-21 12:00:57 +01:00
parent a66772aa63
commit 90b0ff23b7
29 changed files with 873 additions and 763 deletions

View File

@ -1,3 +1,8 @@
2011-01-21 Werner Koch <wk@g10code.com>
* configure.ac: Need Libgcrypt 1.4.6 due to AESWRAP.
(HAVE_GCRY_PK_ECDH): Add new test.
2011-01-03 Werner Koch <wk@g10code.com> 2011-01-03 Werner Koch <wk@g10code.com>
* README.SVN: Rename to README.GIT. * README.SVN: Rename to README.GIT.

View File

@ -1,3 +1,7 @@
2011-01-21 Werner Koch <wk@g10code.com>
* cvt-openpgp.c (GCRY_PK_ECDH) [!HAVE_GCRY_PK_ECDH]: New.
2010-12-02 Werner Koch <wk@g10code.com> 2010-12-02 Werner Koch <wk@g10code.com>
* gpg-agent.c (CHECK_OWN_SOCKET_INTERVAL) [W32CE]: Set to 60 * gpg-agent.c (CHECK_OWN_SOCKET_INTERVAL) [W32CE]: Set to 60

View File

@ -28,6 +28,13 @@
#include "i18n.h" #include "i18n.h"
#include "cvt-openpgp.h" #include "cvt-openpgp.h"
/* Macros for compatibility with older libgcrypt versions. */
#ifndef HAVE_GCRY_PK_ECDSA
# define GCRY_PK_ECDH 302
#endif
/* Helper to pass data via the callback to do_unprotect. */ /* Helper to pass data via the callback to do_unprotect. */
struct try_do_unprotect_arg_s struct try_do_unprotect_arg_s
@ -100,8 +107,8 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
/* Convert a secret key given as algorithm id and an array of key /* Convert a secret key given as algorithm id and an array of key
parameters into our s-expression based format. parameters into our s-expression based format. Note that
pubkey_algo is a libgcrypt ID PUBKEY_ALGO is a standard id and not an OpenPGP id.
*/ */
static gpg_error_t static gpg_error_t
convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey) convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
@ -111,7 +118,8 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
*r_key = NULL; *r_key = NULL;
pubkey_algo = map_pk_openpgp_to_gcry( pubkey_algo ); /* FIXME: This is not consistent with the above comment. */
pubkey_algo = map_pk_openpgp_to_gcry (pubkey_algo);
switch (pubkey_algo) switch (pubkey_algo)
{ {
@ -224,9 +232,9 @@ do_unprotect (const char *passphrase,
*r_key = NULL; *r_key = NULL;
/* Unfortunately, the OpenPGP PK algorithm numbers need to be re-mapped for Libgcrypt /* Unfortunately, the OpenPGP PK algorithm numbers need to be
*/ re-mapped for Libgcrypt. */
pubkey_algo = map_pk_openpgp_to_gcry( pubkey_algo ); pubkey_algo = map_pk_openpgp_to_gcry (pubkey_algo);
/* Count the actual number of MPIs is in the array and set the /* Count the actual number of MPIs is in the array and set the
remainder to NULL for easier processing later on. */ remainder to NULL for easier processing later on. */
@ -655,7 +663,7 @@ convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
string = gcry_sexp_nth_string (list, 1); string = gcry_sexp_nth_string (list, 1);
if (!string) if (!string)
goto bad_seckey; goto bad_seckey;
pubkey_algo = gcry_pk_map_name (string); /* ligcrypt IDs */ pubkey_algo = gcry_pk_map_name (string);
xfree (string); xfree (string);
if (gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey) if (gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
@ -1022,7 +1030,6 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
} }
algo = gcry_pk_map_name (name); algo = gcry_pk_map_name (name);
log_debug ( "convert to openpgp begin for algo=%s\n", name );
xfree (name); xfree (name);
switch (algo) switch (algo)
@ -1052,7 +1059,6 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
err = apply_protection (array, npkey, nskey, passphrase, err = apply_protection (array, npkey, nskey, passphrase,
GCRY_CIPHER_AES, protect_iv, sizeof protect_iv, GCRY_CIPHER_AES, protect_iv, sizeof protect_iv,
3, GCRY_MD_SHA1, salt, s2k_count); 3, GCRY_MD_SHA1, salt, s2k_count);
///log_debug ( "convert to openpgp: after applying protection, err = %d\n", err );
/* Turn it into the transfer key S-expression. Note that we always /* Turn it into the transfer key S-expression. Note that we always
return a protected key. */ return a protected key. */
if (!err) if (!err)
@ -1082,8 +1088,6 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
put_membuf_str (&mbuf, ")\n"); put_membuf_str (&mbuf, ")\n");
put_membuf (&mbuf, "", 1); put_membuf (&mbuf, "", 1);
///log_debug ( "convert to openpgp: calling gcry_sexp_build\n" );
tmpkey = NULL; tmpkey = NULL;
{ {
char *format = get_membuf (&mbuf, NULL); char *format = get_membuf (&mbuf, NULL);
@ -1093,7 +1097,6 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
err = gcry_sexp_build_array (&tmpkey, NULL, format, format_args); err = gcry_sexp_build_array (&tmpkey, NULL, format, format_args);
xfree (format); xfree (format);
} }
///log_debug ( "convert to openpgp: calling gcry_sexp_build before err=%d\n", err );
if (!err) if (!err)
err = gcry_sexp_build (&tmpsexp, NULL, err = gcry_sexp_build (&tmpsexp, NULL,
"(openpgp-private-key\n" "(openpgp-private-key\n"
@ -1106,7 +1109,6 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
(int)sizeof protect_iv, protect_iv, (int)sizeof protect_iv, protect_iv,
(int)sizeof salt, salt, (int)sizeof salt, salt,
countbuf); countbuf);
///log_debug ( "convert to openpgp: after gcry_sexp_build, err = %d\n", err );
gcry_sexp_release (tmpkey); gcry_sexp_release (tmpkey);
if (!err) if (!err)
err = make_canon_sexp_pad (tmpsexp, 0, r_transferkey, r_transferkeylen); err = make_canon_sexp_pad (tmpsexp, 0, r_transferkey, r_transferkeylen);
@ -1116,8 +1118,5 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
for (i=0; i < DIM (array); i++) for (i=0; i < DIM (array); i++)
gcry_mpi_release (array[i]); gcry_mpi_release (array[i]);
log_debug ( "convert to openpgp end with err=%d\n", err );
return err; return err;
} }

View File

@ -2304,6 +2304,8 @@ check_for_running_agent (int silent, int mode)
} }
/* TODO: it is also in misc, which is not linked with the agent */ /* TODO: it is also in misc, which is not linked with the agent */
/* FIXME: The agent should not know about openpgp internals - weel
except for some stuff in cvt-openpgp. */
int int
map_pk_openpgp_to_gcry (int algo) map_pk_openpgp_to_gcry (int algo)
{ {

View File

@ -43,7 +43,7 @@
/* A table containing the information needed to create a protected /* A table containing the information needed to create a protected
private key */ private key. */
static struct { static struct {
const char *algo; const char *algo;
const char *parmlist; const char *parmlist;
@ -428,9 +428,6 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
unsigned char *p; unsigned char *p;
gcry_md_hd_t md; gcry_md_hd_t md;
if (opt.debug & DBG_CRYPTO_VALUE)
log_info ("Protecting key=%s, passphrase=%s\n", plainkey, passphrase);
/* Create an S-expression with the protected-at timestamp. */ /* Create an S-expression with the protected-at timestamp. */
memcpy (timestamp_exp, "(12:protected-at15:", 19); memcpy (timestamp_exp, "(12:protected-at15:", 19);
gnupg_get_isotime (timestamp_exp+19); gnupg_get_isotime (timestamp_exp+19);
@ -459,55 +456,41 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
for (infidx=0; protect_info[infidx].algo for (infidx=0; protect_info[infidx].algo
&& !smatch (&s, n, protect_info[infidx].algo); infidx++) && !smatch (&s, n, protect_info[infidx].algo); infidx++)
; ;
if (!protect_info[infidx].algo) { if (!protect_info[infidx].algo)
log_info ("Unsupported alg %d for protection\n", protect_info[infidx].algo);
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
}
prot_begin = prot_end = NULL; prot_begin = prot_end = NULL;
for (i=0; (c=protect_info[infidx].parmlist[i]); i++) for (i=0; (c=protect_info[infidx].parmlist[i]); i++)
{ {
if (i == protect_info[infidx].prot_from) if (i == protect_info[infidx].prot_from)
prot_begin = s; prot_begin = s;
if (*s != '(') { if (*s != '(')
log_info ("Unbalanced bracket in S-expression #1\n");
return gpg_error (GPG_ERR_INV_SEXP); return gpg_error (GPG_ERR_INV_SEXP);
}
depth++; depth++;
s++; s++;
n = snext (&s); n = snext (&s);
if (!n) { if (!n)
log_info ("Cannot get the length of S-expression field\n");
return gpg_error (GPG_ERR_INV_SEXP); return gpg_error (GPG_ERR_INV_SEXP);
} if (n != 1 || c != *s)
if (n != 1 || c != *s) {
log_info ("Invalid length in S-expression field\n");
return gpg_error (GPG_ERR_INV_SEXP); return gpg_error (GPG_ERR_INV_SEXP);
} s += n;
s += n;
n = snext (&s); n = snext (&s);
if (!n) { if (!n)
log_info ("Invalid fieled in S-expression field\n");
return gpg_error (GPG_ERR_INV_SEXP); return gpg_error (GPG_ERR_INV_SEXP);
}
s +=n; /* skip value */ s +=n; /* skip value */
if (*s != ')') { if (*s != ')')
log_info ("Unbalanced bracket in S-expression #2\n");
return gpg_error (GPG_ERR_INV_SEXP); return gpg_error (GPG_ERR_INV_SEXP);
}
depth--; depth--;
if (i == protect_info[infidx].prot_to) if (i == protect_info[infidx].prot_to)
prot_end = s; prot_end = s;
s++; s++;
} }
if (*s != ')' || !prot_begin || !prot_end ) { if (*s != ')' || !prot_begin || !prot_end )
log_info ("Unbalanced bracket in S-expression #3\n");
return gpg_error (GPG_ERR_INV_SEXP); return gpg_error (GPG_ERR_INV_SEXP);
}
depth--; depth--;
hash_end = s; hash_end = s;
s++; s++;
/* skip to the end of the S-exp */ /* Skip to the end of the S-expression. */
assert (depth == 1); assert (depth == 1);
rc = sskip (&s, &depth); rc = sskip (&s, &depth);
if (rc) if (rc)

View File

@ -23,7 +23,7 @@
#include <ctype.h> #include <ctype.h>
#include "util.h" #include "util.h"
#include "gcrypt.h" #include "gcrypt.h" /* FIXME: really needed? */
#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A')) #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
@ -250,7 +250,10 @@ hex2str_alloc (const char *hexstring, size_t *r_count)
* caller must free with xfree * caller must free with xfree
* Returns NULL on error, never throws * Returns NULL on error, never throws
*/ */
char *mpi2hex( gcry_mpi_t m ) { char *
mpi2hex( gcry_mpi_t m )
{
#warning we have code for this in libcrypt
size_t nbytes; size_t nbytes;
size_t nbytes2; size_t nbytes2;
int rc; int rc;
@ -270,7 +273,9 @@ char *mpi2hex( gcry_mpi_t m ) {
bin2hex( p+2*nbytes+1, nbytes2, p ); bin2hex( p+2*nbytes+1, nbytes2, p );
p[nbytes2*2] = '\0'; p[nbytes2*2] = '\0';
//printf("%s:%d>>>> Created the string %s from %d bytes %02x %02x ..., MPI was %d bytes\n", __FILE__, __LINE__, p, nbytes2, p[2*nbytes+1], p[2*nbytes+2], nbytes); /*printf("%s:%d>>>> Created the string %s from %d bytes %02x %02x
..., MPI was %d bytes\n", __FILE__, __LINE__, p, nbytes2,
p[2*nbytes+1], p[2*nbytes+2], nbytes); */
return p; return p;
} }

View File

@ -24,7 +24,7 @@ min_automake_version="1.10"
# Remember to change the version number immediately *after* a release. # Remember to change the version number immediately *after* a release.
# Set my_issvn to "yes" for non-released code. Remember to run an # Set my_issvn to "yes" for non-released code. Remember to run an
# "svn up" and "autogen.sh" right before creating a distribution. # "svn up" and "autogen.sh" right before creating a distribution.
m4_define([my_version], [2.2.0]) m4_define([my_version], [2.1.0])
m4_define([my_issvn], [yes]) m4_define([my_issvn], [yes])
m4_define([svn_revision], m4_esyscmd([printf "%d" $(svn info 2>/dev/null \ m4_define([svn_revision], m4_esyscmd([printf "%d" $(svn info 2>/dev/null \
@ -43,7 +43,7 @@ development_version=no
NEED_GPG_ERROR_VERSION=1.8 NEED_GPG_ERROR_VERSION=1.8
NEED_LIBGCRYPT_API=1 NEED_LIBGCRYPT_API=1
NEED_LIBGCRYPT_VERSION=1.6.0 NEED_LIBGCRYPT_VERSION=1.4.6
NEED_LIBASSUAN_API=2 NEED_LIBASSUAN_API=2
NEED_LIBASSUAN_VERSION=2.0.0 NEED_LIBASSUAN_VERSION=2.0.0
@ -724,6 +724,20 @@ AM_PATH_GPG_ERROR("$NEED_GPG_ERROR_VERSION",
AM_PATH_LIBGCRYPT("$NEED_LIBGCRYPT_API:$NEED_LIBGCRYPT_VERSION", AM_PATH_LIBGCRYPT("$NEED_LIBGCRYPT_API:$NEED_LIBGCRYPT_VERSION",
have_libgcrypt=yes,have_libgcrypt=no) have_libgcrypt=yes,have_libgcrypt=no)
AC_CACHE_CHECK([whether Libgcrypt support ECDH], gnupg_cv_gcry_pk_ecdh,
[ _gnupg_gcry_save_cflags=$CFLAGS
CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS"
AC_TRY_COMPILE(
[#include <gcrypt>],
[ return GCRY_PK_ECDH; ],
gnupg_cv_gcry_pk_ecdh=yes,
gnupg_cv_gcry_pk_ecdh=no)
CFLAGS=$_gnupg_gcry_save_cflags])
if test "$gnupg_cv_gcry_pk_ecdh" = yes; then
AC_DEFINE([HAVE_GCRY_PK_ECDH], 1,
[Define if gcrypt.h has the enum value for ECDH.])
fi
# #
# libassuan is used for IPC # libassuan is used for IPC

View File

@ -61,7 +61,7 @@ endif
dirmngr_LDADD = $(libcommonpth) ../gl/libgnu.a $(DNSLIBS) $(LIBASSUAN_LIBS) \ dirmngr_LDADD = $(libcommonpth) ../gl/libgnu.a $(DNSLIBS) $(LIBASSUAN_LIBS) \
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(PTH_LIBS) $(LIBINTL) $(LIBICONV) $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(PTH_LIBS) $(LIBINTL) $(LIBICONV)
if !USE_LDAPWRAPPER if !USE_LDAPWRAPPER
dirmngr_LDADD += $(LDAPLIBS) -llber dirmngr_LDADD += $(LDAPLIBS) -llber #FIXME: Test for liblber first.
endif endif
dirmngr_LDFLAGS = $(extra_bin_ldflags) dirmngr_LDFLAGS = $(extra_bin_ldflags)

View File

@ -1079,7 +1079,7 @@ armor_filter( void *opaque, int control,
iobuf_writestr(a,afx->eol); iobuf_writestr(a,afx->eol);
if( !opt.no_version ) if( !opt.no_version )
{ {
iobuf_writestr(a, "Version: GnuPG v" VERSION "-ecc (" iobuf_writestr(a, "Version: GnuPG v" VERSION " ("
PRINTABLE_OS_NAME ")" ); PRINTABLE_OS_NAME ")" );
iobuf_writestr(a,afx->eol); iobuf_writestr(a,afx->eol);
} }

View File

@ -178,21 +178,20 @@ mpi_write (iobuf_t out, gcry_mpi_t a)
return rc; return rc;
} }
/* /* Write the name OID, encoded as an mpi, to OUT. The format of the
* Write the name OID, encoded as an mpi, to OUT. The format of the content of the MPI is * content of the MPI is one byte LEN, following by LEN bytes that are
* one byte LEN, following by LEN bytes that are DER representation of an ASN.1 OID. * DER representation of an ASN.1 OID. This is true for each of the 3
* This is true for each of the 3 following functions. * following functions. */
*/
#define iobuf_name_oid_write iobuf_write_size_body_mpi #define iobuf_name_oid_write iobuf_write_size_body_mpi
/* Write the value of KEK fields for ECDH. */ /* Write the value of KEK fields for ECDH. */
#define ecdh_kek_params_write iobuf_write_size_body_mpi #define ecdh_kek_params_write iobuf_write_size_body_mpi
/* Write the value of encrypted filed for ECDH. */
/* Write the value of encrypted filed for ECDH. */
#define ecdh_esk_write iobuf_write_size_body_mpi #define ecdh_esk_write iobuf_write_size_body_mpi
/**************** /* Calculate the length of a packet described by PKT. */
* calculate the length of a packet described by PKT
*/
u32 u32
calc_packet_length( PACKET *pkt ) calc_packet_length( PACKET *pkt )
{ {
@ -300,24 +299,35 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
} }
assert (npkey < nskey); assert (npkey < nskey);
if( pk->pubkey_algo != PUBKEY_ALGO_ECDSA && pk->pubkey_algo != PUBKEY_ALGO_ECDH ) { /* Writing the public parameters is easy. Except if we do an
/* Writing the public parameters is easy, */ adjustment for ECC OID and possibly KEK params for ECDH. */
for (i=0; i < npkey; i++ ) if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
if ((err = mpi_write (a, pk->pkey[i]))) || pk->pubkey_algo == PUBKEY_ALGO_ECDH)
goto leave;
}
else {
/* ... except we do an adjustment for ECC OID and possibly KEK params for ECDH */
if( (err=iobuf_name_oid_write(a, pk->pkey[0])) || /* DER of OID with preceeding length byte */
(err = mpi_write (a, pk->pkey[1])) ) /* point Q, the public key */
{ {
goto leave; /* Write DER of OID with preceeding length byte. */
err = iobuf_name_oid_write (a, pk->pkey[0]);
if (err)
goto leave;
/* Write point Q, the public key. */
err = mpi_write (a, pk->pkey[1]);
if (err)
goto leave;
/* Write one more public field for ECDH. */
if (pk->pubkey_algo == PUBKEY_ALGO_ECDH)
{
err = ecdh_kek_params_write(a,pk->pkey[2]);
if (err)
goto leave;
}
} }
if( pk->pubkey_algo == PUBKEY_ALGO_ECDH && (err=ecdh_kek_params_write(a,pk->pkey[2]))) { /* one more public field for ECDH */ else
goto leave; {
for (i=0; i < npkey; i++ )
if ((err = mpi_write (a, pk->pkey[i])))
goto leave;
} }
/* followed by possibly protected private scalar */
}
if (pk->seckey_info) if (pk->seckey_info)
{ {
@ -483,22 +493,25 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
if ( !n ) if ( !n )
write_fake_data( a, enc->data[0] ); write_fake_data( a, enc->data[0] );
if( enc->pubkey_algo != PUBKEY_ALGO_ECDH ) { if (enc->pubkey_algo == PUBKEY_ALGO_ECDH )
for (i=0; i < n && !rc ; i++ ) {
rc = mpi_write(a, enc->data[i] ); /* The second field persists as a LEN+field structure, even
} * though it is stored for uniformity as an MPI internally. */
else { assert (n == 2);
/* the second field persists as a LEN+field structure, even though it is rc = mpi_write (a, enc->data[0]);
* stored for uniformity as an MPI internally */ if (!rc)
assert( n==2 ); rc = ecdh_esk_write (a, enc->data[1]);
rc = mpi_write(a, enc->data[0] ); }
if( !rc ) rc = ecdh_esk_write(a, enc->data[1] ); else
} {
for (i=0; i < n && !rc ; i++ )
rc = mpi_write(a, enc->data[i] );
}
if (!rc) if (!rc)
{ {
write_header(out, ctb, iobuf_get_temp_length(a) ); write_header (out, ctb, iobuf_get_temp_length(a) );
rc = iobuf_write_temp( out, a ); rc = iobuf_write_temp (out, a);
} }
iobuf_close(a); iobuf_close(a);
return rc; return rc;

View File

@ -1,5 +1,5 @@
/* ecdh.c - ECDH public key operations used in public key glue code /* ecdh.c - ECDH public key operations used in public key glue code
* Copyright (C) 2000, 2003 Free Software Foundation, Inc. * Copyright (C) 2010 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -31,10 +31,12 @@
#include "options.h" #include "options.h"
gcry_mpi_t gcry_mpi_t
pk_ecdh_default_params_to_mpi( int qbits ) { pk_ecdh_default_params_to_mpi (int qbits)
{
gpg_error_t err; gpg_error_t err;
gcry_mpi_t result; gcry_mpi_t result;
/* Defaults are the strongest possible choices. Performance is not an issue here, only interoperability. */ /* Defaults are the strongest possible choices. Performance is not
an issue here, only interoperability. */
byte kek_params[4] = { byte kek_params[4] = {
3 /*size of following field*/, 3 /*size of following field*/,
1 /*fixed version for KDF+AESWRAP*/, 1 /*fixed version for KDF+AESWRAP*/,
@ -50,41 +52,49 @@ pk_ecdh_default_params_to_mpi( int qbits ) {
} kek_params_table[] = { } kek_params_table[] = {
{ 256, DIGEST_ALGO_SHA256, CIPHER_ALGO_AES }, { 256, DIGEST_ALGO_SHA256, CIPHER_ALGO_AES },
{ 384, DIGEST_ALGO_SHA384, CIPHER_ALGO_AES256 }, { 384, DIGEST_ALGO_SHA384, CIPHER_ALGO_AES256 },
{ 528, DIGEST_ALGO_SHA512, CIPHER_ALGO_AES256 } // 528 is 521 rounded to the 8 bit boundary
/* Note: 528 is 521 rounded to the 8 bit boundary */
{ 528, DIGEST_ALGO_SHA512, CIPHER_ALGO_AES256 }
}; };
for( i=0; i<sizeof(kek_params_table)/sizeof(kek_params_table[0]); i++ ) { for (i=0; i<sizeof(kek_params_table)/sizeof(kek_params_table[0]); i++)
if( kek_params_table[i].qbits >= qbits ) { {
kek_params[2] = kek_params_table[i].openpgp_hash_id; if (kek_params_table[i].qbits >= qbits)
kek_params[3] = kek_params_table[i].openpgp_cipher_id; {
break; kek_params[2] = kek_params_table[i].openpgp_hash_id;
kek_params[3] = kek_params_table[i].openpgp_cipher_id;
break;
}
} }
} if (DBG_CIPHER)
if( DBG_CIPHER ) log_printhex ("ecdh kek params are", kek_params, sizeof(kek_params) );
log_printhex ("ecdh kek params are", kek_params, sizeof(kek_params) );
err = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, kek_params, sizeof(kek_params), NULL); err = gcry_mpi_scan (&result, GCRYMPI_FMT_USG,
kek_params, sizeof(kek_params), NULL);
if (err) if (err)
log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err)); log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err));
return result; return result;
} }
/* returns allocated (binary) KEK parameters; the size is returned in sizeout.
* The caller must free returned value with xfree. /* Returns allocated (binary) KEK parameters; the size is returned in
* Returns NULL on error * sizeout. The caller must free the returned value with xfree.
* Returns NULL on error.
*/ */
byte * byte *
pk_ecdh_default_params( int qbits, size_t *sizeout ) { pk_ecdh_default_params (int qbits, size_t *sizeout)
/* Defaults are the strongest possible choices. Performance is not an issue here, only interoperability. */ {
/* Defaults are the strongest possible choices. Performance is not
an issue here, only interoperability. */
byte kek_params[4] = { byte kek_params[4] = {
3 /*size of following field*/, 3 /*size of following field*/,
1 /*fixed version for KDF+AESWRAP*/, 1 /*fixed version for KDF+AESWRAP*/,
DIGEST_ALGO_SHA512 /* KEK MD */, DIGEST_ALGO_SHA512 /* KEK MD */,
CIPHER_ALGO_AES256 /*KEK AESWRAP alg*/ CIPHER_ALGO_AES256 /* KEK AESWRAP alg */
}; };
int i; int i;
static const struct { static const struct {
int qbits; int qbits;
int openpgp_hash_id; int openpgp_hash_id;
@ -92,39 +102,48 @@ pk_ecdh_default_params( int qbits, size_t *sizeout ) {
} kek_params_table[] = { } kek_params_table[] = {
{ 256, DIGEST_ALGO_SHA256, CIPHER_ALGO_AES }, { 256, DIGEST_ALGO_SHA256, CIPHER_ALGO_AES },
{ 384, DIGEST_ALGO_SHA384, CIPHER_ALGO_AES256 }, { 384, DIGEST_ALGO_SHA384, CIPHER_ALGO_AES256 },
{ 528, DIGEST_ALGO_SHA512, CIPHER_ALGO_AES256 } // 528 is 521 rounded to the 8 bit boundary /* Note: 528 is 521 rounded to the 8 bit boundary */
{ 528, DIGEST_ALGO_SHA512, CIPHER_ALGO_AES256 }
}; };
byte *p; byte *p;
*sizeout = 0; *sizeout = 0;
for( i=0; i<sizeof(kek_params_table)/sizeof(kek_params_table[0]); i++ ) { for (i=0; i<sizeof(kek_params_table)/sizeof(kek_params_table[0]); i++)
if( kek_params_table[i].qbits >= qbits ) { {
kek_params[2] = kek_params_table[i].openpgp_hash_id; if (kek_params_table[i].qbits >= qbits)
kek_params[3] = kek_params_table[i].openpgp_cipher_id; {
break; kek_params[2] = kek_params_table[i].openpgp_hash_id;
kek_params[3] = kek_params_table[i].openpgp_cipher_id;
break;
}
} }
} if (DBG_CIPHER )
if( DBG_CIPHER ) log_printhex ("ecdh kek params are", kek_params, sizeof(kek_params));
log_printhex ("ecdh kek params are", kek_params, sizeof(kek_params) );
p = xtrymalloc( sizeof(kek_params) ); p = xtrymalloc (sizeof(kek_params));
if( p == NULL ) if (!p)
return NULL; return NULL;
memcpy( p, kek_params, sizeof(kek_params) ); memcpy (p, kek_params, sizeof(kek_params));
*sizeout = sizeof(kek_params); *sizeout = sizeof(kek_params);
return p; return p;
} }
/* Encrypts/decrypts 'data' with a key derived from shared_mpi ECC point using FIPS SP 800-56A compliant method, which is
* key derivation + key wrapping. The direction is determined by the first parameter (is_encrypt=1 --> this is encryption). /* Encrypts/decrypts 'data' with a key derived from shared_mpi ECC
* The result is returned in out as a size+value MPI. * point using FIPS SP 800-56A compliant method, which is key
* derivation + key wrapping. The direction is determined by the first
* parameter (is_encrypt=1 --> this is encryption). The result is
* returned in out as a size+value MPI.
*
* TODO: memory leaks (x_secret). * TODO: memory leaks (x_secret).
*/ */
static int static int
pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi, pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t * pkey, gcry_mpi_t *out) const byte pk_fp[MAX_FINGERPRINT_LEN],
gcry_mpi_t data, gcry_mpi_t *pkey,
gcry_mpi_t *out)
{ {
byte *secret_x; byte *secret_x;
int secret_x_size; int secret_x_size;
@ -141,55 +160,70 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
{ {
size_t nbytes; size_t nbytes;
/* extract x component of the shared point: this is the actual shared secret */ /* Extract x component of the shared point: this is the actual
shared secret */
nbytes = (mpi_get_nbits (pkey[1] /* public point */)+7)/8; nbytes = (mpi_get_nbits (pkey[1] /* public point */)+7)/8;
secret_x = xmalloc_secure( nbytes ); secret_x = xmalloc_secure( nbytes );
rc = gcry_mpi_print (GCRYMPI_FMT_USG, secret_x, nbytes, &nbytes, shared_mpi); rc = gcry_mpi_print (GCRYMPI_FMT_USG, secret_x, nbytes,
if( rc ) { &nbytes, shared_mpi);
xfree( secret_x ); if (rc)
log_error ("ec ephemeral export of shared point failed: %s\n", gpg_strerror (rc) ); {
return rc; xfree (secret_x);
} log_error ("ec ephemeral export of shared point failed: %s\n",
gpg_strerror (rc));
return rc;
}
secret_x_size = (nbits+7)/8; secret_x_size = (nbits+7)/8;
assert( nbytes > secret_x_size ); assert (nbytes > secret_x_size);
memmove( secret_x, secret_x+1, secret_x_size ); memmove (secret_x, secret_x+1, secret_x_size);
memset( secret_x+secret_x_size, 0, nbytes-secret_x_size ); memset (secret_x+secret_x_size, 0, nbytes-secret_x_size);
if( DBG_CIPHER ) if (DBG_CIPHER)
log_printhex ("ecdh shared secret X is:", secret_x, secret_x_size ); log_printhex ("ecdh shared secret X is:", secret_x, secret_x_size );
} }
/*** We have now the shared secret bytes in secret_x ***/ /*** We have now the shared secret bytes in secret_x. ***/
/* At this point we are done with PK encryption and the rest of the function uses symmetric /* At this point we are done with PK encryption and the rest of the
* key encryption techniques to protect the input 'data'. The following two sections will * function uses symmetric key encryption techniques to protect the
* simply replace current secret_x with a value derived from it. This will become a KEK. * input 'data'. The following two sections will simply replace
* current secret_x with a value derived from it. This will become
* a KEK.
*/ */
{ {
IOBUF obuf = iobuf_temp(); IOBUF obuf = iobuf_temp();
rc = iobuf_write_size_body_mpi ( obuf, pkey[2] ); /* KEK params */ rc = iobuf_write_size_body_mpi ( obuf, pkey[2] ); /* KEK params */
kdf_params_size = iobuf_temp_to_buffer (obuf,
kdf_params, sizeof(kdf_params));
kdf_params_size = iobuf_temp_to_buffer( obuf, kdf_params, sizeof(kdf_params) ); if (DBG_CIPHER)
log_printhex ("ecdh KDF public key params are:",
kdf_params, kdf_params_size );
if( DBG_CIPHER ) /* Expect 4 bytes 03 01 hash_alg symm_alg. */
log_printhex ("ecdh KDF public key params are:", kdf_params, kdf_params_size ); if (kdf_params_size != 4 || kdf_params[0] != 3 || kdf_params[1] != 1)
if( kdf_params_size != 4 || kdf_params[0] != 3 || kdf_params[1] != 1 ) /* expect 4 bytes 03 01 hash_alg symm_alg */
return GPG_ERR_BAD_PUBKEY; return GPG_ERR_BAD_PUBKEY;
kdf_hash_algo = kdf_params[2]; kdf_hash_algo = kdf_params[2];
kdf_encr_algo = kdf_params[3]; kdf_encr_algo = kdf_params[3];
if( DBG_CIPHER ) if (DBG_CIPHER)
log_debug ("ecdh KDF algorithms %s+%s with aeswrap\n", gcry_md_algo_name (kdf_hash_algo), openpgp_cipher_algo_name (kdf_encr_algo) ); log_debug ("ecdh KDF algorithms %s+%s with aeswrap\n",
gcry_md_algo_name (kdf_hash_algo),
openpgp_cipher_algo_name (kdf_encr_algo));
if( kdf_hash_algo != GCRY_MD_SHA256 && kdf_hash_algo != GCRY_MD_SHA384 && kdf_hash_algo != GCRY_MD_SHA512 ) if (kdf_hash_algo != GCRY_MD_SHA256
&& kdf_hash_algo != GCRY_MD_SHA384
&& kdf_hash_algo != GCRY_MD_SHA512)
return GPG_ERR_BAD_PUBKEY; return GPG_ERR_BAD_PUBKEY;
if( kdf_encr_algo != GCRY_CIPHER_AES128 && kdf_encr_algo != GCRY_CIPHER_AES192 && kdf_encr_algo != GCRY_CIPHER_AES256 ) if (kdf_encr_algo != GCRY_CIPHER_AES128
&& kdf_encr_algo != GCRY_CIPHER_AES192
&& kdf_encr_algo != GCRY_CIPHER_AES256)
return GPG_ERR_BAD_PUBKEY; return GPG_ERR_BAD_PUBKEY;
} }
/* build kdf_params */ /* Build kdf_params. */
{ {
IOBUF obuf; IOBUF obuf;
@ -205,13 +239,15 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
/* fixed-length field 5, recipient fp */ /* fixed-length field 5, recipient fp */
iobuf_write (obuf, pk_fp, 20); iobuf_write (obuf, pk_fp, 20);
kdf_params_size = iobuf_temp_to_buffer( obuf, kdf_params, sizeof(kdf_params) ); kdf_params_size = iobuf_temp_to_buffer (obuf,
iobuf_close( obuf ); kdf_params, sizeof(kdf_params));
if( rc ) { iobuf_close (obuf);
if (rc)
return rc; return rc;
}
if( DBG_CIPHER ) if(DBG_CIPHER)
log_printhex ("ecdh KDF message params are:", kdf_params, kdf_params_size ); log_printhex ("ecdh KDF message params are:",
kdf_params, kdf_params_size );
} }
/* Derive a KEK (key wrapping key) using kdf_params and secret_x. */ /* Derive a KEK (key wrapping key) using kdf_params and secret_x. */
@ -231,7 +267,8 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
assert( gcry_md_get_algo_dlen (kdf_hash_algo) >= 32 ); assert( gcry_md_get_algo_dlen (kdf_hash_algo) >= 32 );
memcpy (secret_x, gcry_md_read (h, kdf_hash_algo), gcry_md_get_algo_dlen (kdf_hash_algo)); memcpy (secret_x, gcry_md_read (h, kdf_hash_algo),
gcry_md_get_algo_dlen (kdf_hash_algo));
gcry_md_close (h); gcry_md_close (h);
old_size = secret_x_size; old_size = secret_x_size;
@ -239,12 +276,13 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
secret_x_size = gcry_cipher_get_algo_keylen( kdf_encr_algo ); secret_x_size = gcry_cipher_get_algo_keylen( kdf_encr_algo );
assert( secret_x_size <= gcry_md_get_algo_dlen (kdf_hash_algo) ); assert( secret_x_size <= gcry_md_get_algo_dlen (kdf_hash_algo) );
memset( secret_x+secret_x_size, old_size-secret_x_size, 0 ); /* we could have allocated more, so clean the tail before returning */ /* We could have allocated more, so clean the tail before returning. */
if( DBG_CIPHER ) memset( secret_x+secret_x_size, old_size-secret_x_size, 0 );
if (DBG_CIPHER)
log_printhex ("ecdh KEK is:", secret_x, secret_x_size ); log_printhex ("ecdh KEK is:", secret_x, secret_x_size );
} }
/* And, finally, aeswrap with key secret_x */ /* And, finally, aeswrap with key secret_x. */
{ {
gcry_cipher_hd_t hd; gcry_cipher_hd_t hd;
size_t nbytes; size_t nbytes;
@ -256,115 +294,134 @@ pk_ecdh_encrypt_with_shared_point ( int is_encrypt, gcry_mpi_t shared_mpi,
rc = gcry_cipher_open (&hd, kdf_encr_algo, GCRY_CIPHER_MODE_AESWRAP, 0); rc = gcry_cipher_open (&hd, kdf_encr_algo, GCRY_CIPHER_MODE_AESWRAP, 0);
if (rc) if (rc)
{ {
log_error( "ecdh failed to initialize AESWRAP: %s\n", gpg_strerror (rc)); log_error ("ecdh failed to initialize AESWRAP: %s\n",
return rc; gpg_strerror (rc));
} return rc;
}
rc = gcry_cipher_setkey (hd, secret_x, secret_x_size); rc = gcry_cipher_setkey (hd, secret_x, secret_x_size);
xfree( secret_x ); xfree( secret_x );
if (rc) if (rc)
{ {
gcry_cipher_close (hd); gcry_cipher_close (hd);
log_error("ecdh failed in gcry_cipher_setkey: %s\n", gpg_strerror (rc)); log_error ("ecdh failed in gcry_cipher_setkey: %s\n",
return rc; gpg_strerror (rc));
} return rc;
}
data_buf_size = (gcry_mpi_get_nbits(data)+7)/8; data_buf_size = (gcry_mpi_get_nbits(data)+7)/8;
assert( (data_buf_size & 7) == (is_encrypt ? 0 : 1) ); assert ((data_buf_size & 7) == (is_encrypt ? 0 : 1));
data_buf = xmalloc_secure( 1 + 2*data_buf_size + 8 ); data_buf = xtrymalloc_secure( 1 + 2*data_buf_size + 8);
if( !data_buf ) { if (!data_buf)
gcry_cipher_close (hd);
return GPG_ERR_ENOMEM;
}
if( is_encrypt ) {
byte *in = data_buf+1+data_buf_size+8;
/* write data MPI into the end of data_buf. data_buf is size aeswrap data */
rc = gcry_mpi_print (GCRYMPI_FMT_USG, in, data_buf_size, &nbytes, data/*in*/);
if( rc ) {
log_error("ecdh failed to export DEK: %s\n", gpg_strerror (rc));
gcry_cipher_close (hd);
xfree( data_buf );
return rc;
}
if( DBG_CIPHER )
log_printhex ("ecdh encrypting :", in, data_buf_size );
rc = gcry_cipher_encrypt (hd, data_buf+1, data_buf_size+8, in, data_buf_size);
memset( in, 0, data_buf_size);
gcry_cipher_close (hd);
if(rc)
{ {
log_error("ecdh failed in gcry_cipher_encrypt: %s\n", gpg_strerror (rc)); gcry_cipher_close (hd);
xfree( data_buf ); return GPG_ERR_ENOMEM;
return rc;
} }
data_buf[0] = data_buf_size+8;
if( DBG_CIPHER ) if (is_encrypt)
{
byte *in = data_buf+1+data_buf_size+8;
/* Write data MPI into the end of data_buf. data_buf is size
aeswrap data. */
rc = gcry_mpi_print (GCRYMPI_FMT_USG, in,
data_buf_size, &nbytes, data/*in*/);
if (rc)
{
log_error ("ecdh failed to export DEK: %s\n", gpg_strerror (rc));
gcry_cipher_close (hd);
xfree (data_buf);
return rc;
}
if (DBG_CIPHER)
log_printhex ("ecdh encrypting :", in, data_buf_size );
rc = gcry_cipher_encrypt (hd, data_buf+1, data_buf_size+8,
in, data_buf_size);
memset (in, 0, data_buf_size);
gcry_cipher_close (hd);
if (rc)
{
log_error ("ecdh failed in gcry_cipher_encrypt: %s\n",
gpg_strerror (rc));
xfree (data_buf);
return rc;
}
data_buf[0] = data_buf_size+8;
if (DBG_CIPHER)
log_printhex ("ecdh encrypted to:", data_buf+1, data_buf[0] ); log_printhex ("ecdh encrypted to:", data_buf+1, data_buf[0] );
rc = gcry_mpi_scan ( &result, GCRYMPI_FMT_USG, data_buf, 1+data_buf[0], NULL); /* (byte)size + aeswrap of DEK */ rc = gcry_mpi_scan (&result, GCRYMPI_FMT_USG,
xfree( data_buf ); data_buf, 1+data_buf[0], NULL);
if(rc) /* (byte)size + aeswrap of DEK */
{
log_error("ecdh failed to create an MPI: %s\n", gpg_strerror (rc));
return rc;
}
*out = result;
}
else {
byte *in;
rc = gcry_mpi_print (GCRYMPI_FMT_USG, data_buf, data_buf_size, &nbytes, data/*in*/);
if( nbytes != data_buf_size || data_buf[0] != data_buf_size-1 ) {
log_error("ecdh inconsistent size\n");
xfree( data_buf ); xfree( data_buf );
return GPG_ERR_BAD_MPI; if (rc)
{
log_error ("ecdh failed to create an MPI: %s\n", gpg_strerror (rc));
return rc;
}
*out = result;
} }
else
{
byte *in;
rc = gcry_mpi_print (GCRYMPI_FMT_USG, data_buf, data_buf_size,
&nbytes, data/*in*/);
if (nbytes != data_buf_size || data_buf[0] != data_buf_size-1)
{
log_error ("ecdh inconsistent size\n");
xfree (data_buf);
return GPG_ERR_BAD_MPI;
}
in = data_buf+data_buf_size; in = data_buf+data_buf_size;
data_buf_size = data_buf[0]; data_buf_size = data_buf[0];
if( DBG_CIPHER )
log_printhex ("ecdh decrypting :", data_buf+1, data_buf_size );
rc = gcry_cipher_decrypt (hd, in, data_buf_size, data_buf+1, data_buf_size ); if (DBG_CIPHER)
log_printhex ("ecdh decrypting :", data_buf+1, data_buf_size);
rc = gcry_cipher_decrypt (hd, in, data_buf_size, data_buf+1,
data_buf_size);
gcry_cipher_close (hd); gcry_cipher_close (hd);
if(rc) if (rc)
{ {
log_error("ecdh failed in gcry_cipher_decrypt: %s\n", gpg_strerror (rc)); log_error ("ecdh failed in gcry_cipher_decrypt: %s\n",
xfree( data_buf ); gpg_strerror (rc));
return rc; xfree (data_buf);
} return rc;
}
data_buf_size-=8; data_buf_size -= 8;
if( DBG_CIPHER ) if (DBG_CIPHER)
log_printhex ("ecdh decrypted to :", in, data_buf_size ); log_printhex ("ecdh decrypted to :", in, data_buf_size);
/* padding is removed later */ /* Padding is removed later. */
//if( in[data_buf_size-1] > 8 ) { /* if (in[data_buf_size-1] > 8 ) */
// log_error("ecdh failed at decryption: invalid padding. %02x > 8\n", in[data_buf_size-1] ); /* { */
// return GPG_ERR_BAD_KEY; /* log_error("ecdh failed at decryption: invalid padding. %02x > 8\n", */
//} /* in[data_buf_size-1] ); */
/* return GPG_ERR_BAD_KEY; */
/* } */
rc = gcry_mpi_scan ( &result, GCRYMPI_FMT_USG, in, data_buf_size, NULL); rc = gcry_mpi_scan ( &result, GCRYMPI_FMT_USG, in, data_buf_size, NULL);
xfree( data_buf ); xfree (data_buf);
if(rc) if (rc)
{ {
log_error("ecdh failed to create a plain text MPI: %s\n", gpg_strerror (rc)); log_error ("ecdh failed to create a plain text MPI: %s\n",
return rc; gpg_strerror (rc));
} return rc;
}
*out = result; *out = result;
} }
} }
return rc; return rc;
} }
@ -380,21 +437,22 @@ gen_k (unsigned nbits)
gcry_mpi_randomize (k, nbits-1, GCRY_STRONG_RANDOM); gcry_mpi_randomize (k, nbits-1, GCRY_STRONG_RANDOM);
if( DBG_CIPHER ) { if (DBG_CIPHER)
unsigned char *buffer; {
if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, k)) unsigned char *buffer;
BUG (); if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, k))
log_debug("ephemeral scalar MPI #0: %s\n", buffer); BUG ();
gcry_free( buffer ); log_debug("ephemeral scalar MPI #0: %s\n", buffer);
} gcry_free( buffer );
}
return k; return k;
} }
/* Perform ECDH encryption, which involves ECDH key generation. /* Perform ECDH encryption, which involves ECDH key generation. */
*/
int int
pk_ecdh_encrypt (gcry_mpi_t * resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t * pkey) pk_ecdh_encrypt (gcry_mpi_t *resarr, const byte pk_fp[MAX_FINGERPRINT_LEN],
gcry_mpi_t data, gcry_mpi_t * pkey)
{ {
gcry_sexp_t s_ciph, s_data, s_pkey; gcry_sexp_t s_ciph, s_data, s_pkey;
@ -402,9 +460,9 @@ pk_ecdh_encrypt (gcry_mpi_t * resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcr
int rc; int rc;
gcry_mpi_t k; gcry_mpi_t k;
nbits = pubkey_nbits( PUBKEY_ALGO_ECDH, pkey ); nbits = pubkey_nbits (PUBKEY_ALGO_ECDH, pkey);
/*** Generate an ephemeral key, actually, a scalar ***/ /*** Generate an ephemeral key, actually, a scalar. ***/
k = gen_k (nbits); k = gen_k (nbits);
if( k == NULL ) if( k == NULL )
@ -414,50 +472,63 @@ pk_ecdh_encrypt (gcry_mpi_t * resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcr
* Now use ephemeral secret to get the shared secret. ***/ * Now use ephemeral secret to get the shared secret. ***/
rc = gcry_sexp_build (&s_pkey, NULL, rc = gcry_sexp_build (&s_pkey, NULL,
"(public-key(ecdh(c%m)(q%m)(p%m)))", pkey[0], pkey[1], pkey[2]); "(public-key(ecdh(c%m)(q%m)(p%m)))",
pkey[0], pkey[1], pkey[2]);
if (rc) if (rc)
BUG (); BUG ();
/* put the data into a simple list */ /* Put the data into a simple list. */
if (gcry_sexp_build (&s_data, NULL, "%m", k)) /* ephemeral scalar goes as data */ /* Ephemeral scalar goes as data. */
if (gcry_sexp_build (&s_data, NULL, "%m", k))
BUG (); BUG ();
/* pass it to libgcrypt */ /* Pass it to libgcrypt. */
rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey); rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
gcry_sexp_release (s_data); gcry_sexp_release (s_data);
gcry_sexp_release (s_pkey); gcry_sexp_release (s_pkey);
if (rc) if (rc)
return rc; return rc;
/* finally, perform encryption */ /* Finally, perform encryption. */
{ {
gcry_mpi_t shared = mpi_from_sexp (s_ciph, "a"); /* ... and get the shared point */ /* ... and get the shared point/ */
gcry_sexp_release (s_ciph); gcry_mpi_t shared;
resarr[0] = mpi_from_sexp (s_ciph, "b"); /* ephemeral public key */
if( DBG_CIPHER ) { shared = mpi_from_sexp (s_ciph, "a");
gcry_sexp_release (s_ciph);
/* Ephemeral public key. */
resarr[0] = mpi_from_sexp (s_ciph, "b");
if (DBG_CIPHER)
{
unsigned char *buffer; unsigned char *buffer;
if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, resarr[0])) if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, resarr[0]))
BUG (); BUG ();
log_debug("ephemeral key MPI: %s\n", buffer); log_debug("ephemeral key MPI: %s\n", buffer);
gcry_free( buffer ); gcry_free( buffer );
} }
rc = pk_ecdh_encrypt_with_shared_point ( 1 /*=encrypton*/, shared, pk_fp, data, pkey, resarr+1 ); rc = pk_ecdh_encrypt_with_shared_point (1 /*=encrypton*/, shared,
mpi_release( shared ); pk_fp, data, pkey, resarr+1);
mpi_release (shared);
} }
return rc; return rc;
} }
/* Perform ECDH decryption.
*/ /* Perform ECDH decryption. */
int int
pk_ecdh_decrypt (gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t shared, gcry_mpi_t * skey) { pk_ecdh_decrypt (gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN],
gcry_mpi_t data, gcry_mpi_t shared, gcry_mpi_t * skey)
{
if (!data) if (!data)
return gpg_error (GPG_ERR_BAD_MPI); return gpg_error (GPG_ERR_BAD_MPI);
return pk_ecdh_encrypt_with_shared_point ( 0 /*=decryption*/, shared, sk_fp, data/*encr data as an MPI*/, skey, result ); return pk_ecdh_encrypt_with_shared_point (0 /*=decryption*/, shared,
sk_fp, data/*encr data as an MPI*/,
skey, result);
} }

View File

@ -894,8 +894,8 @@ write_pubkey_enc_from_list (PK_LIST pk_list, DEK *dek, iobuf_t out)
compliance_failure(); compliance_failure();
} }
fingerprint_from_pk( pk, fp, &fpn ); fingerprint_from_pk (pk, fp, &fpn);
assert( fpn == 20 ); assert (fpn == 20);
/* Okay, what's going on: We have the session key somewhere in /* Okay, what's going on: We have the session key somewhere in
* the structure DEK and want to encode this session key in an * the structure DEK and want to encode this session key in an

View File

@ -1161,18 +1161,16 @@ build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent)
/* iobuf_put (out,')'); iobuf_put (out,'\n'); */ /* iobuf_put (out,')'); iobuf_put (out,'\n'); */
/* (*indent)--; */ /* (*indent)--; */
/* } */ /* } */
/* /* else if (sk->pubkey_algo == PUBKEY_ALGO_ECDSA && !sk->is_protected) */
else if (sk->pubkey_algo == PUBKEY_ALGO_ECDSA && !sk->is_protected) /* { */
{ /* write_sexp_line (out, indent, "(ecdsa\n"); */
write_sexp_line (out, indent, "(ecdsa\n"); /* (*indent)++; */
(*indent)++; /* write_sexp_keyparm (out, indent, "c", sk->skey[0]); iobuf_put (out,'\n'); */
write_sexp_keyparm (out, indent, "c", sk->skey[0]); iobuf_put (out,'\n'); /* write_sexp_keyparm (out, indent, "q", sk->skey[6]); iobuf_put (out,'\n'); */
write_sexp_keyparm (out, indent, "q", sk->skey[6]); iobuf_put (out,'\n'); /* write_sexp_keyparm (out, indent, "d", sk->skey[7]); */
write_sexp_keyparm (out, indent, "d", sk->skey[7]); /* iobuf_put (out,')'); iobuf_put (out,'\n'); */
iobuf_put (out,')'); iobuf_put (out,'\n'); /* (*indent)--; */
(*indent)--; /* } */
}
*/
/* else if (is_ELGAMAL (sk->pubkey_algo) && !sk->is_protected) */ /* else if (is_ELGAMAL (sk->pubkey_algo) && !sk->is_protected) */
/* { */ /* { */
/* write_sexp_line (out, indent, "(elg\n"); */ /* write_sexp_line (out, indent, "(elg\n"); */

View File

@ -813,7 +813,7 @@ my_strusage( int level )
const char *p; const char *p;
switch( level ) { switch( level ) {
case 11: p = "gpg (GnuPG) ecc"; case 11: p = "gpg (GnuPG)";
break; break;
case 13: p = VERSION; break; case 13: p = VERSION; break;
case 17: p = PRINTABLE_OS_NAME; break; case 17: p = PRINTABLE_OS_NAME; break;

View File

@ -18,6 +18,7 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>. * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/ */
#warning wk: check these changes.
#include <config.h> #include <config.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -43,7 +44,6 @@
#include "keyserver-internal.h" #include "keyserver-internal.h"
#include "call-agent.h" #include "call-agent.h"
#include "pkglue.h" #include "pkglue.h"
#include "gcrypt.h"
/* The default algorithms. If you change them remember to change them /* The default algorithms. If you change them remember to change them
also in gpg.c:gpgconf_list. You should also check that the value also in gpg.c:gpgconf_list. You should also check that the value

View File

@ -54,11 +54,11 @@ pubkey_letter( int algo )
case PUBKEY_ALGO_RSA: return 'R' ; case PUBKEY_ALGO_RSA: return 'R' ;
case PUBKEY_ALGO_RSA_E: return 'r' ; case PUBKEY_ALGO_RSA_E: return 'r' ;
case PUBKEY_ALGO_RSA_S: return 's' ; case PUBKEY_ALGO_RSA_S: return 's' ;
case PUBKEY_ALGO_ELGAMAL_E: return 'g'; case PUBKEY_ALGO_ELGAMAL_E: return 'g' ;
case PUBKEY_ALGO_ELGAMAL: return 'G' ; case PUBKEY_ALGO_ELGAMAL: return 'G' ;
case PUBKEY_ALGO_DSA: return 'D' ; case PUBKEY_ALGO_DSA: return 'D' ;
case PUBKEY_ALGO_ECDSA: return 'E' ; // ECC DSA (sign only) case PUBKEY_ALGO_ECDSA: return 'E' ; /* ECC DSA (sign only) */
case PUBKEY_ALGO_ECDH: return 'e' ; // ECC DH (encrypt only) case PUBKEY_ALGO_ECDH: return 'e' ; /* ECC DH (encrypt only) */
default: return '?'; default: return '?';
} }
} }
@ -76,8 +76,6 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
unsigned int nbits; unsigned int nbits;
size_t nbytes; size_t nbytes;
int npkey = pubkey_get_npkey (pk->pubkey_algo); int npkey = pubkey_get_npkey (pk->pubkey_algo);
/* name OID, MPI of public point, [for ECDH only: KEK params] */
enum gcry_mpi_format ecc_pub_format[3] = {GCRYMPI_FMT_USG, GCRYMPI_FMT_PGP, GCRYMPI_FMT_USG};
/* Two extra bytes for the expiration date in v3 */ /* Two extra bytes for the expiration date in v3 */
if(pk->version<4) if(pk->version<4)
@ -92,11 +90,17 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
} }
else else
{ {
for(i=0; i < npkey; i++ ) for (i=0; i < npkey; i++ )
{ {
const enum gcry_mpi_format fmt = enum gcry_mpi_format fmt;
((pk->pubkey_algo==PUBKEY_ALGO_ECDSA || pk->pubkey_algo==PUBKEY_ALGO_ECDH) ? ecc_pub_format[i] : GCRYMPI_FMT_PGP);
if ((pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
&& (i == 0 || i == 2))
fmt = GCRYMPI_FMT_USG; /* Name of OID or KEK parms. */
else
fmt = GCRYMPI_FMT_PGP;
if (gcry_mpi_print (fmt, NULL, 0, &nbytes, pk->pkey[i])) if (gcry_mpi_print (fmt, NULL, 0, &nbytes, pk->pkey[i]))
BUG (); BUG ();
pp[i] = xmalloc (nbytes); pp[i] = xmalloc (nbytes);
@ -106,7 +110,7 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
n += nn[i]; n += nn[i];
} }
} }
gcry_md_putc ( md, 0x99 ); /* ctb */ gcry_md_putc ( md, 0x99 ); /* ctb */
/* What does it mean if n is greater than than 0xFFFF ? */ /* What does it mean if n is greater than than 0xFFFF ? */
gcry_md_putc ( md, n >> 8 ); /* 2 byte length header */ gcry_md_putc ( md, n >> 8 ); /* 2 byte length header */
@ -724,13 +728,12 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
"(public-key(ecc(c%m)(q%m)))", "(public-key(ecc(c%m)(q%m)))",
pk->pkey[0], pk->pkey[1]); pk->pkey[0], pk->pkey[1]);
break; break;
/*
case PUBKEY_ALGO_ECDH: /* case PUBKEY_ALGO_ECDH: */
err = gcry_sexp_build (&s_pkey, NULL, /* err = gcry_sexp_build (&s_pkey, NULL, */
"(public-key(ecdh(c%m)(q%m)(p%m)))", /* "(public-key(ecdh(c%m)(q%m)(p%m)))", */
pk->pkey[0], pk->pkey[1], pk->pkey[2]); /* pk->pkey[0], pk->pkey[1], pk->pkey[2]); */
break; /* break; */
*/
default: default:
err = gpg_error (GPG_ERR_PUBKEY_ALGO); err = gpg_error (GPG_ERR_PUBKEY_ALGO);

View File

@ -87,9 +87,12 @@ u16 checksum_mpi( gcry_mpi_t a );
u32 buffer_to_u32( const byte *buffer ); u32 buffer_to_u32( const byte *buffer );
const byte *get_session_marker( size_t *rlen ); const byte *get_session_marker( size_t *rlen );
int map_cipher_openpgp_to_gcry (int algo); int map_cipher_openpgp_to_gcry (int algo);
#define openpgp_cipher_open(_a,_b,_c,_d) gcry_cipher_open((_a),map_cipher_openpgp_to_gcry((_b)),(_c),(_d)) #define openpgp_cipher_open(_a,_b,_c,_d) \
#define openpgp_cipher_get_algo_keylen(_a) gcry_cipher_get_algo_keylen(map_cipher_openpgp_to_gcry((_a))) gcry_cipher_open((_a),map_cipher_openpgp_to_gcry((_b)),(_c),(_d))
#define openpgp_cipher_get_algo_blklen(_a) gcry_cipher_get_algo_blklen(map_cipher_openpgp_to_gcry((_a))) #define openpgp_cipher_get_algo_keylen(_a) \
gcry_cipher_get_algo_keylen(map_cipher_openpgp_to_gcry((_a)))
#define openpgp_cipher_get_algo_blklen(_a) \
gcry_cipher_get_algo_blklen(map_cipher_openpgp_to_gcry((_a)))
int openpgp_cipher_blocklen (int algo); int openpgp_cipher_blocklen (int algo);
int openpgp_cipher_test_algo( int algo ); int openpgp_cipher_test_algo( int algo );
const char *openpgp_cipher_algo_name (int algo); const char *openpgp_cipher_algo_name (int algo);
@ -159,7 +162,8 @@ int pubkey_get_nenc( int algo );
unsigned int pubkey_nbits( int algo, gcry_mpi_t *pkey ); unsigned int pubkey_nbits( int algo, gcry_mpi_t *pkey );
int mpi_print (estream_t stream, gcry_mpi_t a, int mode); int mpi_print (estream_t stream, gcry_mpi_t a, int mode);
int iobuf_write_size_body_mpi (iobuf_t out, gcry_mpi_t a); int iobuf_write_size_body_mpi (iobuf_t out, gcry_mpi_t a);
int iobuf_read_size_body(iobuf_t inp, byte *body, int body_max_size, int pktlen, gcry_mpi_t *out); int iobuf_read_size_body (iobuf_t inp, byte *body, int body_max_size,
int pktlen, gcry_mpi_t *out);
int ecdsa_qbits_from_Q( int qbits ); int ecdsa_qbits_from_Q( int qbits );
@ -258,7 +262,9 @@ int save_unprotected_key_to_card (PKT_public_key *sk, int keyno);
#define KEYGEN_FLAG_NO_PROTECTION 1 #define KEYGEN_FLAG_NO_PROTECTION 1
#define KEYGEN_FLAG_TRANSIENT_KEY 2 #define KEYGEN_FLAG_TRANSIENT_KEY 2
int pk_ecc_keypair_gen( PKT_public_key **pk_out, int algo, int keygen_flags, char **cache_nonce_addr, unsigned nbits); int pk_ecc_keypair_gen (PKT_public_key **pk_out, int algo,
int keygen_flags, char **cache_nonce_addr,
unsigned nbits);
/*-- openfile.c --*/ /*-- openfile.c --*/
int overwrite_filep( const char *fname ); int overwrite_filep( const char *fname );

View File

@ -1,6 +1,6 @@
/* misc.c - miscellaneous functions /* misc.c - miscellaneous functions
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
* 2008, 2009 Free Software Foundation, Inc. * 2008, 2009, 2010 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -366,10 +366,17 @@ map_cipher_gcry_to_openpgp (int algo)
} }
} }
/* Map OpenPGP public key algorithm numbers to those used by
Libgcrypt. */
int int
map_pk_openpgp_to_gcry (int algo) map_pk_openpgp_to_gcry (int algo)
{ {
return (algo==PUBKEY_ALGO_ECDSA ? GCRY_PK_ECDSA : (algo==PUBKEY_ALGO_ECDH ? GCRY_PK_ECDH : algo)); switch (algo)
{
case PUBKEY_ALGO_ECDSA: return GCRY_PK_ECDSA;
case PUBKEY_ALGO_ECDH: return GCRY_PK_ECDH;
default: return algo;
}
} }
@ -416,13 +423,7 @@ openpgp_cipher_test_algo( int algo )
const char * const char *
openpgp_cipher_algo_name (int algo) openpgp_cipher_algo_name (int algo)
{ {
return gcry_cipher_algo_name (map_cipher_openpgp_to_gcry (algo)); return gnupg_cipher_algo_name (map_cipher_openpgp_to_gcry (algo));
}
const char *
openpgp_pk_algo_name (int algo)
{
return gcry_pk_algo_name ( algo == PUBKEY_ALGO_ECDSA ? GCRY_PK_ECDSA : ( algo == PUBKEY_ALGO_ECDH ? GCRY_PK_ECDH : algo ) );
} }
int int
@ -438,12 +439,7 @@ openpgp_pk_test_algo( int algo )
if (algo < 0 || algo > 110) if (algo < 0 || algo > 110)
return gpg_error (GPG_ERR_PUBKEY_ALGO); return gpg_error (GPG_ERR_PUBKEY_ALGO);
if( algo == PUBKEY_ALGO_ECDSA ) return gcry_pk_test_algo (map_pk_openpgp_to_gcry (algo));
algo = GCRY_PK_ECDSA;
else if( algo == PUBKEY_ALGO_ECDH )
algo = GCRY_PK_ECDH;
return gcry_pk_test_algo ( algo );
} }
int int
@ -461,12 +457,8 @@ openpgp_pk_test_algo2( int algo, unsigned int use )
if (algo < 0 || algo > 110) if (algo < 0 || algo > 110)
return gpg_error (GPG_ERR_PUBKEY_ALGO); return gpg_error (GPG_ERR_PUBKEY_ALGO);
if( algo == PUBKEY_ALGO_ECDSA ) return gcry_pk_algo_info (map_pk_openpgp_to_gcry (algo),
algo = GCRY_PK_ECDSA; GCRYCTL_TEST_ALGO, NULL, &use_buf);
else if( algo == PUBKEY_ALGO_ECDH )
algo = GCRY_PK_ECDH;
return gcry_pk_algo_info ( algo, GCRYCTL_TEST_ALGO, NULL, &use_buf);
} }
int int
@ -507,10 +499,12 @@ openpgp_pk_algo_usage ( int algo )
/* Map the OpenPGP pubkey algorithm whose ID is contained in ALGO to a /* Map the OpenPGP pubkey algorithm whose ID is contained in ALGO to a
string representation of the algorithm name. For unknown algorithm string representation of the algorithm name. For unknown algorithm
IDs this function returns "?". IDs this function returns "?". */
const char * const char *
openpgp_pk_algo_name (int algo) openpgp_pk_algo_name (int algo)
{ {
/* We use fixed strings to have pretty names instead of those from
libgcrypt. */
switch (algo) switch (algo)
{ {
case PUBKEY_ALGO_RSA: case PUBKEY_ALGO_RSA:
@ -522,10 +516,13 @@ openpgp_pk_algo_name (int algo)
case PUBKEY_ALGO_DSA: return "dsa"; case PUBKEY_ALGO_DSA: return "dsa";
default: return "?"; case PUBKEY_ALGO_ECDSA:return "ecdsa";
case PUBKEY_ALGO_ECDH: return "ecdh";
default: gcry_pk_algo_name (map_pk_openpgp_to_gcry (algo));
} }
} }
*/
int int
@ -1444,6 +1441,7 @@ pubkey_nbits( int algo, gcry_mpi_t *key )
int rc, nbits; int rc, nbits;
gcry_sexp_t sexp; gcry_sexp_t sexp;
#warning Why this assert
assert( algo != GCRY_PK_ECDSA && algo != GCRY_PK_ECDH ); assert( algo != GCRY_PK_ECDSA && algo != GCRY_PK_ECDH );
if( algo == GCRY_PK_DSA ) { if( algo == GCRY_PK_DSA ) {
@ -1506,10 +1504,12 @@ mpi_print (estream_t fp, gcry_mpi_t a, int mode)
return n; return n;
} }
/* /*
* Write a special size+body mpi a, to OUT. The format of the content of the MPI is * Write a special size+body mpi A, to OUT. The format of the content
* one byte LEN, following by LEN bytes * of the MPI is one byte LEN, following by LEN bytes.
*/ */
/* FIXME: Rename this function: it is not in iobuf.c */
int int
iobuf_write_size_body_mpi (iobuf_t out, gcry_mpi_t a) iobuf_write_size_body_mpi (iobuf_t out, gcry_mpi_t a)
{ {
@ -1538,57 +1538,68 @@ iobuf_write_size_body_mpi (iobuf_t out, gcry_mpi_t a)
return iobuf_write( out, buffer, nbytes ); return iobuf_write( out, buffer, nbytes );
} }
/* /*
* Read a special size+body from inp into body[body_max_size] and return it in a buffer and as MPI. * Read a special size+body from inp into body[body_max_size] and
* On success the number of consumed bytes will body[0]+1. * return it in a buffer and as MPI. On success the number of
* The format of the content of the returned MPI is one byte LEN, following by LEN bytes. * consumed bytes will body[0]+1. The format of the content of the
* Caller is expected to pre-allocate fixed-size 255 byte buffer (or smaller when appropriate). * returned MPI is one byte LEN, following by LEN bytes. Caller is
* expected to pre-allocate fixed-size 255 byte buffer (or smaller
* when appropriate).
*/ */
/* FIXME: Rename this function: it is not in iobuf.c */
int int
iobuf_read_size_body( iobuf_t inp, byte *body, int body_max_size, int pktlen, gcry_mpi_t *out ) { iobuf_read_size_body (iobuf_t inp, byte *body, int body_max_size,
int pktlen, gcry_mpi_t *out )
{
unsigned n; unsigned n;
int rc; int rc;
gcry_mpi_t result; gcry_mpi_t result;
*out = NULL; *out = NULL;
if( (n = iobuf_readbyte(inp)) == -1 ) { if( (n = iobuf_readbyte(inp)) == -1 )
return G10ERR_INVALID_PACKET; {
} return G10ERR_INVALID_PACKET;
if( n >= body_max_size || n < 2) { }
log_error("invalid size+body field\n"); if ( n >= body_max_size || n < 2)
return G10ERR_INVALID_PACKET; {
} log_error("invalid size+body field\n");
return G10ERR_INVALID_PACKET;
}
body[0] = n; body[0] = n;
if( (n = iobuf_read(inp, body+1, n)) == -1 ) { if ((n = iobuf_read(inp, body+1, n)) == -1)
log_error("invalid size+body field\n"); {
return G10ERR_INVALID_PACKET; log_error("invalid size+body field\n");
} return G10ERR_INVALID_PACKET;
if( n+1 > pktlen ) { }
log_error("size+body field is larger than the packet\n"); if (n+1 > pktlen)
return G10ERR_INVALID_PACKET; {
} log_error("size+body field is larger than the packet\n");
return G10ERR_INVALID_PACKET;
}
rc = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, body, n+1, NULL); rc = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, body, n+1, NULL);
if (rc) if (rc)
log_fatal ("mpi_scan failed: %s\n", gpg_strerror (rc)); log_fatal ("mpi_scan failed: %s\n", gpg_strerror (rc));
*out = result; *out = result;
return rc; return rc;
} }
/* pkey[1] or skey[1] is Q for ECDSA, which is an uncompressed point, i.e. 04 <x> <y> */ /* pkey[1] or skey[1] is Q for ECDSA, which is an uncompressed point,
int ecdsa_qbits_from_Q( int qbits ) { i.e. 04 <x> <y> */
if( qbits%8>3 ) { int
log_error(_("ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n")); ecdsa_qbits_from_Q (int qbits )
return 0; {
} if ((qbits%8) > 3)
qbits -= qbits%8; {
qbits /= 2; log_error(_("ECDSA public key is expected to be in SEC encoding "
return qbits; "multiple of 8 bits\n"));
return 0;
}
qbits -= qbits%8;
qbits /= 2;
return qbits;
} }

View File

@ -939,40 +939,47 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
} }
else else
{ {
if( k->pubkey_algo != PUBKEY_ALGO_ECDH ) { if (k->pubkey_algo == PUBKEY_ALGO_ECDH)
for (i = 0; i < ndata; i++)
{
n = pktlen;
k->data[i] = mpi_read (inp, &n, 0);
pktlen -= n;
if (list_mode)
{
es_fprintf (listfp, "\tdata: ");
mpi_print (listfp, k->data[i], mpi_print_mode);
es_putc ('\n', listfp);
}
if (!k->data[i])
rc = gpg_error (GPG_ERR_INV_PACKET);
}
}
else
{ {
byte encr_buf[255]; byte encr_buf[255];
assert( ndata == 2 );
n = pktlen; k->data[0] = mpi_read(inp, &n, 0); pktlen -=n; assert (ndata == 2);
rc = iobuf_read_size_body( inp, encr_buf, sizeof(encr_buf), pktlen, k->data+1 ); n = pktlen;
if( rc ) k->data[0] = mpi_read (inp, &n, 0);
goto leave; pktlen -= n;
if( list_mode ) { rc = iobuf_read_size_body (inp, encr_buf, sizeof(encr_buf),
es_fprintf (listfp, "\tdata: "); pktlen, k->data+1);
mpi_print(listfp, k->data[0], mpi_print_mode ); if (rc)
es_putc ('\n', listfp); goto leave;
es_fprintf (listfp, "\tdata: [% 3d bytes] ", encr_buf[0]+1);
mpi_print(listfp, k->data[1], mpi_print_mode ); if (list_mode)
es_putc ('\n', listfp); {
} es_fprintf (listfp, "\tdata: ");
pktlen -= (encr_buf[0]+1); mpi_print (listfp, k->data[0], mpi_print_mode );
} es_putc ('\n', listfp);
es_fprintf (listfp, "\tdata: [% 3d bytes] ", encr_buf[0]+1);
mpi_print (listfp, k->data[1], mpi_print_mode );
es_putc ('\n', listfp);
}
pktlen -= (encr_buf[0]+1);
}
else
{
for (i = 0; i < ndata; i++)
{
n = pktlen;
k->data[i] = mpi_read (inp, &n, 0);
pktlen -= n;
if (list_mode)
{
es_fprintf (listfp, "\tdata: ");
mpi_print (listfp, k->data[i], mpi_print_mode);
es_putc ('\n', listfp);
}
if (!k->data[i])
rc = gpg_error (GPG_ERR_INV_PACKET);
}
}
} }
leave: leave:
@ -1946,61 +1953,74 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
else else
{ {
/* Fill in public key parameters. */ /* Fill in public key parameters. */
if( algorithm != PUBKEY_ALGO_ECDSA && algorithm != PUBKEY_ALGO_ECDH ) { if (algorithm == PUBKEY_ALGO_ECDSA && algorithm == PUBKEY_ALGO_ECDH)
for (i = 0; i < npkey; i++) {
{ /* FIXME: The code in this function ignores the errors. */
n = pktlen; byte name_oid[256];
pk->pkey[i] = mpi_read (inp, &n, 0);
pktlen -= n; err = iobuf_read_size_body (inp, name_oid, sizeof(name_oid),
if (list_mode) pktlen, pk->pkey+0);
{ if (err)
es_fprintf (listfp, "\tpkey[%d]: ", i); goto leave;
mpi_print (listfp, pk->pkey[i], mpi_print_mode); n = name_oid[0];
es_putc ('\n', listfp); if (list_mode)
} es_fprintf (listfp, "\tpkey[0]: curve OID [%d] ...%02x %02x\n",
if (!pk->pkey[i]) n, name_oid[1+n-2], name_oid[1+n-1]);
err = gpg_error (GPG_ERR_INV_PACKET); pktlen -= (n+1);
} /* Set item [1], which corresponds to the public key; these
} two fields are all we need to uniquely define the key/ */
else { n = pktlen;
/* note that the code in this function ignores the errors */ pk->pkey[1] = mpi_read( inp, &n, 0 );
byte name_oid[256]; pktlen -=n;
err = iobuf_read_size_body( inp, name_oid, sizeof(name_oid), pktlen, pk->pkey+0 ); if (!pk->pkey[1])
if( err ) err = gpg_error (GPG_ERR_INV_PACKET);
goto leave; else if (list_mode)
n = name_oid[0]; {
if( list_mode ) es_fprintf (listfp, "\tpkey[1]: ");
es_fprintf (listfp, "\tpkey[0]: curve OID [%d] ...%02x %02x\n", mpi_print (listfp, pk->pkey[1], mpi_print_mode);
n, name_oid[1+n-2], name_oid[1+n-1] ); es_putc ('\n', listfp);
pktlen -= (n+1);
/* set item [1], which corresponds to the public key; these two fields are all we need to uniquely define the key */
// log_debug("Parsing ecc public key in the public packet, pktlen=%lu\n", pktlen);
n = pktlen; pk->pkey[1] = mpi_read( inp, &n, 0 ); pktlen -=n;
if( pk->pkey[1]==NULL )
err = gpg_error(G10ERR_INVALID_PACKET);
else if( list_mode ) {
es_fprintf (listfp, "\tpkey[1]: ");
mpi_print(listfp, pk->pkey[1], mpi_print_mode);
es_putc ('\n', listfp);
} }
/* One more field for ECDH */ /* One more field for ECDH. */
if( algorithm == PUBKEY_ALGO_ECDH ) { if (algorithm == PUBKEY_ALGO_ECDH)
#define kek_params name_oid {
err = iobuf_read_size_body( inp, kek_params, sizeof(kek_params), pktlen, pk->pkey+2 ); /* (NAMEOID holds the KEK params.) */
if( err ) err = iobuf_read_size_body (inp, name_oid, sizeof(name_oid),
goto leave; pktlen, pk->pkey+2);
n = kek_params[0]; if (err)
if( kek_params[1] != 1 ) { goto leave;
log_error("invalid ecdh KEK parameters field type in private key: understand type 1, but found 0x%02x\n", kek_params[1]); n = name_oid[0];
err = gpg_error(G10ERR_INVALID_PACKET); if (name_oid[1] != 1)
goto leave; {
} log_error ("invalid ecdh KEK parameters field type in "
if( list_mode ) "private key: understand type 1, "
es_fprintf (listfp, "\tpkey[2]: KEK params type=01 hash:%d sym-algo:%d\n", kek_params[1+n-2], kek_params[1+n-1] ); "but found 0x%02x\n", name_oid[1]);
pktlen -= (n+1); err = gpg_error (GPG_ERR_INV_PACKET);
#undef kek_params goto leave;
} }
} if (list_mode)
es_fprintf (listfp, "\tpkey[2]: KEK params type=01 "
"hash:%d sym-algo:%d\n",
name_oid[1+n-2], name_oid[1+n-1]);
pktlen -= (n+1);
}
}
else
{
for (i = 0; i < npkey; i++)
{
n = pktlen;
pk->pkey[i] = mpi_read (inp, &n, 0);
pktlen -= n;
if (list_mode)
{
es_fprintf (listfp, "\tpkey[%d]: ", i);
mpi_print (listfp, pk->pkey[i], mpi_print_mode);
es_putc ('\n', listfp);
}
if (!pk->pkey[i])
err = gpg_error (GPG_ERR_INV_PACKET);
}
}
if (err) if (err)
goto leave; goto leave;
} }

View File

@ -1,5 +1,5 @@
/* pkglue.c - public key operations glue code /* pkglue.c - public key operations glue code
* Copyright (C) 2000, 2003 Free Software Foundation, Inc. * Copyright (C) 2000, 2003, 2010 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -29,7 +29,8 @@
#include "pkglue.h" #include "pkglue.h"
#include "main.h" #include "main.h"
/* FIXME: Better chnage the fucntion name because mpi_ is used by
gcrypt macros. */
gcry_mpi_t gcry_mpi_t
mpi_from_sexp (gcry_sexp_t sexp, const char * item) mpi_from_sexp (gcry_sexp_t sexp, const char * item)
{ {
@ -45,101 +46,37 @@ mpi_from_sexp (gcry_sexp_t sexp, const char * item)
} }
/****************
* Emulate our old PK interface here - sometime in the future we might
* change the internal design to directly fit to libgcrypt.
*/
int
pk_sign (int algo, gcry_mpi_t * data, gcry_mpi_t hash, gcry_mpi_t * skey)
{
gcry_sexp_t s_sig, s_hash, s_skey;
int rc;
int gcry_pkalgo = map_pk_openpgp_to_gcry( algo );
/* make a sexp from skey */
if (gcry_pkalgo == GCRY_PK_DSA)
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
skey[0], skey[1], skey[2], skey[3], skey[4]);
}
else if (gcry_pkalgo == GCRY_PK_RSA || gcry_pkalgo == GCRY_PK_RSA_S)
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
skey[0], skey[1], skey[2], skey[3], skey[4],
skey[5]);
}
else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
skey[0], skey[1], skey[2], skey[3]);
}
else if (gcry_pkalgo == GCRY_PK_ECDSA)
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(ecdsa(c%m)(q%m)(d%m)))",
skey[0], skey[1], skey[2] );
}
else
return GPG_ERR_PUBKEY_ALGO;
if (rc)
BUG ();
/* put hash into a S-Exp s_hash */
if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
BUG ();
rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
gcry_sexp_release (s_hash);
gcry_sexp_release (s_skey);
if (rc)
;
else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_S)
data[0] = mpi_from_sexp (s_sig, "s");
else
{
data[0] = mpi_from_sexp (s_sig, "r");
data[1] = mpi_from_sexp (s_sig, "s");
}
gcry_sexp_release (s_sig);
return rc;
}
/**************** /****************
* Emulate our old PK interface here - sometime in the future we might * Emulate our old PK interface here - sometime in the future we might
* change the internal design to directly fit to libgcrypt. * change the internal design to directly fit to libgcrypt.
*/ */
int int
pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey) pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey)
{ {
gcry_sexp_t s_sig, s_hash, s_pkey; gcry_sexp_t s_sig, s_hash, s_pkey;
int rc; int rc;
const int gcry_pkalgo = map_pk_openpgp_to_gcry( algo ); const int pkalgo = map_pk_openpgp_to_gcry (algo);
/* make a sexp from pkey */ /* Make a sexp from pkey. */
if (gcry_pkalgo == GCRY_PK_DSA) if (pkalgo == GCRY_PK_DSA)
{ {
rc = gcry_sexp_build (&s_pkey, NULL, rc = gcry_sexp_build (&s_pkey, NULL,
"(public-key(dsa(p%m)(q%m)(g%m)(y%m)))", "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
pkey[0], pkey[1], pkey[2], pkey[3]); pkey[0], pkey[1], pkey[2], pkey[3]);
} }
else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E) else if (pkalgo == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E)
{ {
rc = gcry_sexp_build (&s_pkey, NULL, rc = gcry_sexp_build (&s_pkey, NULL,
"(public-key(elg(p%m)(g%m)(y%m)))", "(public-key(elg(p%m)(g%m)(y%m)))",
pkey[0], pkey[1], pkey[2]); pkey[0], pkey[1], pkey[2]);
} }
else if (gcry_pkalgo == GCRY_PK_RSA || gcry_pkalgo == GCRY_PK_RSA_S) else if (pkalgo == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_S)
{ {
rc = gcry_sexp_build (&s_pkey, NULL, rc = gcry_sexp_build (&s_pkey, NULL,
"(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]); "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
} }
else if (gcry_pkalgo == GCRY_PK_ECDSA) /* same as GCRY_PK_ECDH */ else if (pkalgo == GCRY_PK_ECDSA) /* Same as GCRY_PK_ECDH */
{ {
rc = gcry_sexp_build (&s_pkey, NULL, rc = gcry_sexp_build (&s_pkey, NULL,
"(public-key(ecdsa(c%m)(q%m)))", pkey[0], pkey[1]); "(public-key(ecdsa(c%m)(q%m)))", pkey[0], pkey[1]);
@ -150,13 +87,13 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
if (rc) if (rc)
BUG (); /* gcry_sexp_build should never fail. */ BUG (); /* gcry_sexp_build should never fail. */
/* put hash into a S-Exp s_hash */ /* Put hash into a S-Exp s_hash. */
if (gcry_sexp_build (&s_hash, NULL, "%m", hash)) if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
BUG (); /* gcry_sexp_build should never fail. */ BUG (); /* gcry_sexp_build should never fail. */
/* Put data into a S-Exp s_sig. */ /* Put data into a S-Exp s_sig. */
s_sig = NULL; s_sig = NULL;
if (gcry_pkalgo == GCRY_PK_DSA) if (pkalgo == GCRY_PK_DSA)
{ {
if (!data[0] || !data[1]) if (!data[0] || !data[1])
rc = gpg_error (GPG_ERR_BAD_MPI); rc = gpg_error (GPG_ERR_BAD_MPI);
@ -164,7 +101,7 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
rc = gcry_sexp_build (&s_sig, NULL, rc = gcry_sexp_build (&s_sig, NULL,
"(sig-val(dsa(r%m)(s%m)))", data[0], data[1]); "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]);
} }
else if (gcry_pkalgo == GCRY_PK_ECDSA) else if (pkalgo == GCRY_PK_ECDSA)
{ {
if (!data[0] || !data[1]) if (!data[0] || !data[1])
rc = gpg_error (GPG_ERR_BAD_MPI); rc = gpg_error (GPG_ERR_BAD_MPI);
@ -172,7 +109,7 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
rc = gcry_sexp_build (&s_sig, NULL, rc = gcry_sexp_build (&s_sig, NULL,
"(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]); "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]);
} }
else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E) else if (pkalgo == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E)
{ {
if (!data[0] || !data[1]) if (!data[0] || !data[1])
rc = gpg_error (GPG_ERR_BAD_MPI); rc = gpg_error (GPG_ERR_BAD_MPI);
@ -180,7 +117,7 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
rc = gcry_sexp_build (&s_sig, NULL, rc = gcry_sexp_build (&s_sig, NULL,
"(sig-val(elg(r%m)(s%m)))", data[0], data[1]); "(sig-val(elg(r%m)(s%m)))", data[0], data[1]);
} }
else if (gcry_pkalgo == GCRY_PK_RSA || gcry_pkalgo == GCRY_PK_RSA_S) else if (pkalgo == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_S)
{ {
if (!data[0]) if (!data[0])
rc = gpg_error (GPG_ERR_BAD_MPI); rc = gpg_error (GPG_ERR_BAD_MPI);
@ -207,12 +144,13 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
* change the internal design to directly fit to libgcrypt. * change the internal design to directly fit to libgcrypt.
*/ */
int int
pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t * pkey) pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t *pkey)
{ {
gcry_sexp_t s_ciph, s_data, s_pkey; gcry_sexp_t s_ciph, s_data, s_pkey;
int rc; int rc;
/* make a sexp from pkey */ /* Make a sexp from pkey. */
if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E) if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
{ {
rc = gcry_sexp_build (&s_pkey, NULL, rc = gcry_sexp_build (&s_pkey, NULL,
@ -227,7 +165,7 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, const byte pk_fp[MAX
} }
else if (algo == PUBKEY_ALGO_ECDH) else if (algo == PUBKEY_ALGO_ECDH)
{ {
return pk_ecdh_encrypt( resarr, pk_fp, data, pkey ); return pk_ecdh_encrypt (resarr, pk_fp, data, pkey);
} }
else else
return GPG_ERR_PUBKEY_ALGO; return GPG_ERR_PUBKEY_ALGO;
@ -235,11 +173,11 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, const byte pk_fp[MAX
if (rc) if (rc)
BUG (); BUG ();
/* put the data into a simple list */ /* Put the data into a simple list. */
if (gcry_sexp_build (&s_data, NULL, "%m", data)) if (gcry_sexp_build (&s_data, NULL, "%m", data))
BUG (); BUG ();
/* pass it to libgcrypt */ /* Pass it to libgcrypt. */
rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey); rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
gcry_sexp_release (s_data); gcry_sexp_release (s_data);
gcry_sexp_release (s_pkey); gcry_sexp_release (s_pkey);
@ -247,9 +185,11 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, const byte pk_fp[MAX
if (rc) if (rc)
; ;
else else
{ /* add better error handling or make gnupg use S-Exp directly */ { /* Add better error handling or make gnupg use S-Exp directly. */
resarr[0] = mpi_from_sexp (s_ciph, "a"); resarr[0] = mpi_from_sexp (s_ciph, "a");
if (algo != GCRY_PK_RSA && algo != GCRY_PK_RSA_E && algo != PUBKEY_ALGO_ECDH) if (algo != GCRY_PK_RSA
&& algo != GCRY_PK_RSA_E
&& algo != PUBKEY_ALGO_ECDH)
resarr[1] = mpi_from_sexp (s_ciph, "b"); resarr[1] = mpi_from_sexp (s_ciph, "b");
} }
@ -257,6 +197,7 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, const byte pk_fp[MAX
return rc; return rc;
} }
/* Check whether SKEY is a suitable secret key. */ /* Check whether SKEY is a suitable secret key. */
int int
pk_check_secret_key (int algo, gcry_mpi_t *skey) pk_check_secret_key (int algo, gcry_mpi_t *skey)

View File

@ -1,5 +1,5 @@
/* pkglue.h - public key operations definitions /* pkglue.h - public key operations definitions
* Copyright (C) 2003 Free Software Foundation, Inc. * Copyright (C) 2003, 2010 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -22,21 +22,19 @@
gcry_mpi_t mpi_from_sexp (gcry_sexp_t sexp, const char * item); gcry_mpi_t mpi_from_sexp (gcry_sexp_t sexp, const char * item);
int pk_sign (int algo, gcry_mpi_t *data, gcry_mpi_t hash,
gcry_mpi_t *skey);
int pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, int pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data,
gcry_mpi_t *pkey); gcry_mpi_t *pkey);
int pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, int pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
const byte fp[MAX_FINGERPRINT_LEN], const byte fp[MAX_FINGERPRINT_LEN],
gcry_mpi_t *pkey); gcry_mpi_t *pkey);
int pk_decrypt (int algo, gcry_mpi_t *result, const byte fp[MAX_FINGERPRINT_LEN], gcry_mpi_t *data,
gcry_mpi_t *skey);
int pk_check_secret_key (int algo, gcry_mpi_t *skey); int pk_check_secret_key (int algo, gcry_mpi_t *skey);
int pk_ecdh_encrypt (gcry_mpi_t * resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t * pkey); int pk_ecdh_encrypt (gcry_mpi_t *resarr, const byte pk_fp[MAX_FINGERPRINT_LEN],
int pk_ecdh_decrypt (gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t shared, gcry_mpi_t * skey); gcry_mpi_t data, gcry_mpi_t * pkey);
int pk_ecdh_decrypt (gcry_mpi_t *result, const byte sk_fp[MAX_FINGERPRINT_LEN],
gcry_mpi_t data, gcry_mpi_t shared, gcry_mpi_t * skey);
gcry_mpi_t pk_ecdh_default_params_to_mpi( int qbits ); gcry_mpi_t pk_ecdh_default_params_to_mpi (int qbits);
byte *pk_ecdh_default_params( int qbits, size_t *sizeout ); byte *pk_ecdh_default_params (int qbits, size_t *sizeout);
#endif /*GNUPG_G10_PKGLUE_H*/ #endif /*GNUPG_G10_PKGLUE_H*/

View File

@ -218,68 +218,72 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
log_printhex ("DEK frame:", frame, nframe); log_printhex ("DEK frame:", frame, nframe);
n = 0; n = 0;
if( sk->pubkey_algo != PUBKEY_ALGO_ECDH ) { if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
if (!card) {
{ gcry_mpi_t shared_mpi;
if (n + 7 > nframe) gcry_mpi_t decoded;
{
err = gpg_error (G10ERR_WRONG_SECKEY); /* At the beginning the frame are the bytes of shared point MPI. */
goto leave; err = gcry_mpi_scan (&shared_mpi, GCRYMPI_FMT_USG, frame, nframe, NULL);
} if (err)
if (frame[n] == 1 && frame[nframe - 1] == 2) {
{ log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err));
log_info (_("old encoding of the DEK is not supported\n")); goto leave;
err = gpg_error (G10ERR_CIPHER_ALGO); }
goto leave;
}
if (frame[n] != 2) /* Something went wrong. */
{
err = gpg_error (G10ERR_WRONG_SECKEY);
goto leave;
}
for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes. */
;
n++; /* Skip the zero byte. */
}
}
else {
gcry_mpi_t shared_mpi;
gcry_mpi_t decoded;
/* at the beginning the frame is the bytes of shared point MPI */ err = pk_ecdh_decrypt (&decoded, fp, enc->data[1]/*encr data as an MPI*/,
shared_mpi, sk->pkey);
err = gcry_mpi_scan (&shared_mpi, GCRYMPI_FMT_USG, frame, nframe, NULL); mpi_release (shared_mpi);
if (err) { if(err)
log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err)); goto leave;
goto leave;
/* Reuse NFRAME, which size is sufficient to include the session key. */
err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &nframe, decoded);
mpi_release (decoded);
if (err)
goto leave;
/* Now the frame are the bytes decrypted but padded session key. */
/* Allow double padding for the benefit of DEK size concealment.
Higher than this is wasteful. */
if (frame[nframe-1] > 8*2 || nframe <= 8)
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
nframe -= frame[nframe-1]; /* Remove padding. */
assert (n); /* (used just below) */
} }
else
err = pk_ecdh_decrypt (&decoded, fp, enc->data[1]/*encr data as an MPI*/, shared_mpi, sk->pkey); {
mpi_release( shared_mpi ); if (!card)
if( err ) {
goto leave; if (n + 7 > nframe)
{
/* reuse nframe, which size is sufficient to include the session key */ err = gpg_error (GPG_ERR_WRONG_SECKEY);
err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &nframe, decoded); goto leave;
mpi_release( decoded ); }
if( err ) if (frame[n] == 1 && frame[nframe - 1] == 2)
goto leave; {
log_info (_("old encoding of the DEK is not supported\n"));
/* Now the frame is the bytes decrypted but padded session key */ err = gpg_error (GPG_ERR_CIPHER_ALGO);
goto leave;
/* Allow double padding for the benefit of DEK size concealment. }
* Higher than this is wasteful. if (frame[n] != 2) /* Something went wrong. */
*/ {
if( frame[nframe-1] > 8*2 || nframe <= 8 ) { err = gpg_error (GPG_ERR_WRONG_SECKEY);
err = G10ERR_WRONG_SECKEY; goto leave; goto leave;
}
for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes. */
;
n++; /* Skip the zero byte. */
}
} }
nframe -= frame[nframe-1]; /* remove padding */
assert( n==0 ); /* used just bellow */
}
if (n + 4 > nframe) if (n + 4 > nframe)
{ {
err = gpg_error (G10ERR_WRONG_SECKEY); err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave; goto leave;
} }

View File

@ -1,6 +1,6 @@
/* seskey.c - make sesssion keys etc. /* seskey.c - make sesssion keys etc.
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
* 2006, 2009 Free Software Foundation, Inc. * 2006, 2009, 2010 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -76,109 +76,125 @@ make_session_key( DEK *dek )
gcry_mpi_t gcry_mpi_t
encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits) encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
{ {
size_t nframe = (nbits+7) / 8; size_t nframe = (nbits+7) / 8;
byte *p; byte *p;
byte *frame; byte *frame;
int i,n; int i,n;
u16 csum = 0; u16 csum;
gcry_mpi_t a; gcry_mpi_t a;
if (DBG_CIPHER)
log_debug ("encode_session_key: encoding %d byte DEK", dek->keylen);
if( DBG_CIPHER ) csum = 0;
log_debug("encode_session_key: encoding %d byte DEK", dek->keylen); for (p = dek->key, i=0; i < dek->keylen; i++)
csum += *p++;
for( p = dek->key, i=0; i < dek->keylen; i++ ) /* Shortcut for ECDH. It's padding is minimal to simply make the
csum += *p++; output be a multiple of 8 bytes. */
if (openpgp_pk_algo == PUBKEY_ALGO_ECDH)
{
/* Pad to 8 byte granulatiry; the padding byte is the number of
* padded bytes.
*
* A DEK(k bytes) CSUM(2 bytes) 0x 0x 0x 0x ... 0x
* +---- x times ---+
*/
nframe = (( 1 + dek->keylen + 2 /* The value so far is always odd. */
+ 7 ) & (~7));
/* alg+key+csum fit and the size is congruent to 8. */
assert (!(nframe%8) && nframe > 1 + dek->keylen + 2 );
frame = xmalloc_secure (nframe);
n = 0;
frame[n++] = dek->algo;
memcpy (frame+n, dek->key, dek->keylen);
n += dek->keylen;
frame[n++] = csum >> 8;
frame[n++] = csum;
i = nframe - n; /* Number of padded bytes. */
memset (frame+n, i, i); /* Use it as the value of each padded byte. */
assert (n+i == nframe);
/* Shortcut for ECDH. It's padding is minimal to simply make the output be a multiple of 8 bytes. */ if (DBG_CIPHER)
if( openpgp_pk_algo == PUBKEY_ALGO_ECDH ) { log_debug ("encode_session_key: "
/* pad to 8 byte granulatiry; the padding byte is the number of padded bytes. "[%d] %02x %02x %02x ... %02x %02x %02x\n",
* A DEK(k bytes) CSUM(2 bytes) 0x 0x 0x 0x ... 0x nframe, frame[0], frame[1], frame[2],
* +---- x times ---+ frame[nframe-3], frame[nframe-2], frame[nframe-1]);
*/
nframe = ( 1 + dek->keylen + 2 /* the value so far is always odd */ + 7 ) & (~7); if (gcry_mpi_scan (&a, GCRYMPI_FMT_USG, frame, nframe, &nframe))
assert( !(nframe%8) && nframe > 1 + dek->keylen + 2 ); /* alg+key+csum fit and the size is congruent to 8 */ BUG();
frame = xmalloc_secure( nframe ); xfree(frame);
n = 0; return a;
frame[n++] = dek->algo;
memcpy( frame+n, dek->key, dek->keylen ); n += dek->keylen;
frame[n++] = csum >>8;
frame[n++] = csum;
i = nframe - n; /* number padded bytes */
memset( frame+n, i, i );/* use it as the value of each padded byte */
assert( n+i == nframe );
if( DBG_CIPHER )
log_debug("encode_session_key: [%d] %02x %02x %02x ... %02x %02x %02x", nframe, frame[0],frame[1],frame[2], frame[nframe-3],frame[nframe-2],frame[nframe-1]);
if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, nframe, &nframe))
BUG();
xfree(frame);
return a;
} }
/* The current limitation is that we can only use a session key
* whose length is a multiple of BITS_PER_MPI_LIMB
* I think we can live with that.
*/
if (dek->keylen + 7 > nframe || !nframe)
log_bug ("can't encode a %d bit key in a %d bits frame\n",
dek->keylen*8, nbits );
/* We encode the session key in this way:
*
* 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes)
*
* (But how can we store the leading 0 - the external representaion
* of MPIs doesn't allow leading zeroes =:-)
*
* RND are non-zero random bytes.
* A is the cipher algorithm
* DEK is the encryption key (session key) length k depends on the
* cipher algorithm (20 is used with blowfish160).
* CSUM is the 16 bit checksum over the DEK
*/
/* The current limitation is that we can only use a session key frame = xmalloc_secure( nframe );
* whose length is a multiple of BITS_PER_MPI_LIMB n = 0;
* I think we can live with that. frame[n++] = 0;
*/ frame[n++] = 2;
if( dek->keylen + 7 > nframe || !nframe ) i = nframe - 6 - dek->keylen;
log_bug("can't encode a %d bit key in a %d bits frame\n", assert( i > 0 );
dek->keylen*8, nbits ); p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
/* Replace zero bytes by new values. */
/* We encode the session key in this way: for (;;)
* {
* 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes) int j, k;
* byte *pp;
* (But how can we store the leading 0 - the external representaion
* of MPIs doesn't allow leading zeroes =:-) /* Count the zero bytes. */
* for (j=k=0; j < i; j++ )
* RND are non-zero random bytes. if (!p[j])
* A is the cipher algorithm k++;
* DEK is the encryption key (session key) length k depends on the if (!k)
* cipher algorithm (20 is used with blowfish160). break; /* Okay: no zero bytes. */
* CSUM is the 16 bit checksum over the DEK k += k/128 + 3; /* Better get some more. */
*/ pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
for (j=0; j < i && k ;)
frame = xmalloc_secure( nframe ); {
n = 0; if (!p[j])
frame[n++] = 0; p[j] = pp[--k];
frame[n++] = 2; if (p[j])
i = nframe - 6 - dek->keylen; j++;
assert( i > 0 );
p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
/* Replace zero bytes by new values. */
for(;;) {
int j, k;
byte *pp;
/* count the zero bytes */
for(j=k=0; j < i; j++ )
if( !p[j] )
k++;
if( !k )
break; /* okay: no zero bytes */
k += k/128 + 3; /* better get some more */
pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
for(j=0; j < i && k ;) {
if( !p[j] )
p[j] = pp[--k];
if (p[j])
j++;
} }
xfree(pp); xfree (pp);
} }
memcpy( frame+n, p, i ); memcpy (frame+n, p, i);
xfree(p); xfree (p);
n += i; n += i;
frame[n++] = 0; frame[n++] = 0;
frame[n++] = dek->algo; frame[n++] = dek->algo;
memcpy( frame+n, dek->key, dek->keylen ); n += dek->keylen; memcpy (frame+n, dek->key, dek->keylen );
frame[n++] = csum >>8; n += dek->keylen;
frame[n++] = csum; frame[n++] = csum >>8;
assert( n == nframe ); frame[n++] = csum;
if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, n, &nframe)) assert (n == nframe);
BUG(); if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, n, &nframe))
xfree(frame); BUG();
return a; xfree (frame);
return a;
} }
@ -192,8 +208,8 @@ do_encode_md( gcry_md_hd_t md, int algo, size_t len, unsigned nbits,
gcry_mpi_t a; gcry_mpi_t a;
if( len + asnlen + 4 > nframe ) if( len + asnlen + 4 > nframe )
log_bug("can't encode a %d bit MD into a %d bits frame, algo=%d\n", log_bug ("can't encode a %d bit MD into a %d bits frame, algo=%d\n",
(int)(len*8), (int)nbits, algo); (int)(len*8), (int)nbits, algo);
/* We encode the MD in this way: /* We encode the MD in this way:
* *
@ -240,26 +256,27 @@ gcry_mpi_t
encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo) encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
{ {
gcry_mpi_t frame; gcry_mpi_t frame;
int gcry_pkalgo; int pkalgo;
assert (hash_algo); assert (hash_algo);
assert (pk); assert (pk);
gcry_pkalgo = map_pk_openpgp_to_gcry( pk->pubkey_algo ); pkalgo = map_pk_openpgp_to_gcry (pk->pubkey_algo);
if (gcry_pkalgo == GCRY_PK_DSA || gcry_pkalgo == GCRY_PK_ECDSA ) if (pkalgo == GCRY_PK_DSA || pkalgo == GCRY_PK_ECDSA)
{ {
/* It's a DSA signature, so find out the size of q. */ /* It's a DSA signature, so find out the size of q. */
size_t qbytes = gcry_mpi_get_nbits (pk->pkey[1]); size_t qbytes = gcry_mpi_get_nbits (pk->pkey[1]);
/* pkey[1] is Q for ECDSA, which is an uncompressed point, i.e. 04 <x> <y> */ /* pkey[1] is Q for ECDSA, which is an uncompressed point,
if( gcry_pkalgo==GCRY_PK_ECDSA ) i.e. 04 <x> <y> */
qbytes = ecdsa_qbits_from_Q( qbytes ); if (pkalgo == GCRY_PK_ECDSA)
qbytes = ecdsa_qbits_from_Q (qbytes);
/* Make sure it is a multiple of 8 bits. */ /* Make sure it is a multiple of 8 bits. */
if(qbytes%8) if (qbytes%8)
{ {
log_error(_("DSA requires the hash length to be a" log_error(_("DSA requires the hash length to be a"
" multiple of 8 bits\n")); " multiple of 8 bits\n"));
@ -275,30 +292,38 @@ encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
if (qbytes < 160) if (qbytes < 160)
{ {
log_error (_("%s key %s uses an unsafe (%zu bit) hash\n"), log_error (_("%s key %s uses an unsafe (%zu bit) hash\n"),
gcry_pk_algo_name( gcry_pkalgo ), gcry_pk_algo_name (pkalgo), keystr_from_pk (pk), qbytes);
keystr_from_pk (pk), qbytes);
return NULL; return NULL;
} }
qbytes /= 8; qbytes /= 8;
/* Check if we're too short. Too long is safe as we'll /* Check if we're too short. Too long is safe as we'll
automatically left-truncate. */ automatically left-truncate.
/* This checks would require the use of SHA512 with ECDSA 512. I think this is overkill to fail in this case.
* Therefore, relax the check, but only for ECDSA keys. We may need to adjust it later for general case. FIXME: Check against FIPS.
* ( Note that the check will never pass for ECDSA 521 anyway as the only hash that intended to match it is SHA 512, but 512 < 521 ). This checks would require the use of SHA512 with ECDSA 512. I
*/ think this is overkill to fail in this case. Therefore,
if (gcry_md_get_algo_dlen (hash_algo) < ((gcry_pkalgo==GCRY_PK_ECDSA && qbytes>(521)/8) ? 512/8 : qbytes) ) relax the check, but only for ECDSA keys. We may need to
adjust it later for general case. (Note that the check will
never pass for ECDSA 521 anyway as the only hash that
intended to match it is SHA 512, but 512 < 521). */
if (gcry_md_get_algo_dlen (hash_algo)
< ((pkalgo == GCRY_PK_ECDSA && qbytes > (521)/8) ? 512/8 : qbytes))
{ {
log_error (_("%s key %s requires a %zu bit or larger hash, used hash-algo=%d\n"), log_error (_("%s key %s requires a %zu bit or larger hash "
gcry_pk_algo_name( gcry_pkalgo ), "(hash is %s\n"),
keystr_from_pk(pk), qbytes*8, hash_algo); gcry_pk_algo_name (pkalgo),
keystr_from_pk(pk), qbytes*8,
gcry_md_algo_name (hash_algo));
return NULL; return NULL;
} }
/* Note that in case of ECDSA 521 hash is always smaller than the key size */ /* Note that in case of ECDSA 521 hash is always smaller than
the key size. */
if (gcry_mpi_scan (&frame, GCRYMPI_FMT_USG, if (gcry_mpi_scan (&frame, GCRYMPI_FMT_USG,
gcry_md_read (md, hash_algo), gcry_md_get_algo_dlen (hash_algo), &qbytes)) gcry_md_read (md, hash_algo),
gcry_md_get_algo_dlen (hash_algo), &qbytes))
BUG(); BUG();
} }
else else

View File

@ -436,14 +436,15 @@ hash_for (PKT_public_key *pk)
{ {
return recipient_digest_algo; return recipient_digest_algo;
} }
else if(pk->pubkey_algo==PUBKEY_ALGO_DSA || pk->pubkey_algo==PUBKEY_ALGO_ECDSA ) else if (pk->pubkey_algo == PUBKEY_ALGO_DSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
{ {
unsigned int qbytes = gcry_mpi_get_nbits (pk->pkey[1]); unsigned int qbytes = gcry_mpi_get_nbits (pk->pkey[1]);
if( pk->pubkey_algo==PUBKEY_ALGO_ECDSA ) if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
qbytes = ecdsa_qbits_from_Q(qbytes); qbytes = ecdsa_qbits_from_Q (qbytes);
qbytes = qbytes/8; qbytes = qbytes/8;
/* It's a DSA key, so find a hash that is the same size as q or /* It's a DSA key, so find a hash that is the same size as q or
larger. If q is 160, assume it is an old DSA key and use a larger. If q is 160, assume it is an old DSA key and use a
160-bit hash unless --enable-dsa2 is set, in which case act 160-bit hash unless --enable-dsa2 is set, in which case act
@ -924,12 +925,14 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next )
{ {
if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA || sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA ) if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA
|| sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
{ {
int temp_hashlen = gcry_mpi_get_nbits(sk_rover->pk->pkey[1]); int temp_hashlen = (gcry_mpi_get_nbits
(sk_rover->pk->pkey[1]));
if( sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA ) if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
temp_hashlen = ecdsa_qbits_from_Q( temp_hashlen ); temp_hashlen = ecdsa_qbits_from_Q (temp_hashlen);
temp_hashlen = (temp_hashlen+7)/8; temp_hashlen = (temp_hashlen+7)/8;
/* Pick a hash that is large enough for our /* Pick a hash that is large enough for our
@ -1482,13 +1485,14 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
if(opt.cert_digest_algo) if(opt.cert_digest_algo)
digest_algo=opt.cert_digest_algo; digest_algo=opt.cert_digest_algo;
else if(pksk->pubkey_algo==PUBKEY_ALGO_RSA else if(pksk->pubkey_algo == PUBKEY_ALGO_RSA
&& pk->version<4 && sigversion<4) && pk->version<4 && sigversion<4)
digest_algo = DIGEST_ALGO_MD5; digest_algo = DIGEST_ALGO_MD5;
else if(pksk->pubkey_algo==PUBKEY_ALGO_DSA) else if(pksk->pubkey_algo == PUBKEY_ALGO_DSA)
digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8 ); digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8);
else if(pksk->pubkey_algo==PUBKEY_ALGO_ECDSA ) else if(pksk->pubkey_algo == PUBKEY_ALGO_ECDSA )
digest_algo = match_dsa_hash (ecdsa_qbits_from_Q( gcry_mpi_get_nbits (pksk->pkey[1]) ) / 8); digest_algo = match_dsa_hash (ecdsa_qbits_from_Q
(gcry_mpi_get_nbits (pksk->pkey[1]))/8);
else else
digest_algo = DIGEST_ALGO_SHA1; digest_algo = DIGEST_ALGO_SHA1;
} }

View File

@ -1,6 +1,5 @@
/* To satisfy the linker for the gpgv target /* To satisfy the linker for the gpgv target
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, * Copyright (C) 2010 Free Software Foundation, Inc.
* 2007 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -25,6 +24,8 @@
#include "main.h" #include "main.h"
int int
pk_ecc_keypair_gen( PKT_public_key **pk_out, int algo, int keygen_flags, char **cache_nonce_addr, unsigned nbits) { pk_ecc_keypair_gen (PKT_public_key **pk_out, int algo, int keygen_flags,
return GPG_ERR_NOT_IMPLEMENTED; char **cache_nonce_addr, unsigned nbits)
{
return GPG_ERR_NOT_IMPLEMENTED;
} }

View File

@ -176,7 +176,5 @@ next_tuple (tupledesc_t tupledesc, unsigned int *r_tag, size_t *r_length)
} }
return NULL; return NULL;
} }

View File

@ -1,3 +1,9 @@
2011-01-21 Werner Koch <wk@g10code.com>
* cipher.h (GCRY_PK_USAGE_CERT): Remove comaptibility macros
because we now require libgcrypt 1.4.6.
(GCRY_PK_ECDH): Add replacement.
2009-08-20 Daiki Ueno <ueno@unixuser.org> (wk) 2009-08-20 Daiki Ueno <ueno@unixuser.org> (wk)
* cipher.h (struct DEK): Add field S2K_CACHEID. * cipher.h (struct DEK): Add field S2K_CACHEID.

View File

@ -1,6 +1,6 @@
/* cipher.h - Definitions for OpenPGP /* cipher.h - Definitions for OpenPGP
* Copyright (C) 1998, 1999, 2000, 2001, 2006, * Copyright (C) 1998, 1999, 2000, 2001, 2006,
* 2007 Free Software Foundation, Inc. * 2007, 2010 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -23,10 +23,8 @@
#include <gcrypt.h> #include <gcrypt.h>
/* Macros for compatibility with older libgcrypt versions. */ /* Macros for compatibility with older libgcrypt versions. */
#ifndef GCRY_PK_USAGE_CERT #ifndef HAVE_GCRY_PK_ECDSA
# define GCRY_PK_USAGE_CERT 4 # define GCRY_PK_ECDH 302
# define GCRY_PK_USAGE_AUTH 8
# define GCRY_PK_USAGE_UNKN 128
#endif #endif
@ -56,8 +54,8 @@
#define PUBKEY_ALGO_RSA_S /* 3 */ GCRY_PK_RSA_S /* RSA sign only. */ #define PUBKEY_ALGO_RSA_S /* 3 */ GCRY_PK_RSA_S /* RSA sign only. */
#define PUBKEY_ALGO_ELGAMAL_E /* 16 */ GCRY_PK_ELG_E /* Elgamal encr only */ #define PUBKEY_ALGO_ELGAMAL_E /* 16 */ GCRY_PK_ELG_E /* Elgamal encr only */
#define PUBKEY_ALGO_DSA /* 17 */ GCRY_PK_DSA #define PUBKEY_ALGO_DSA /* 17 */ GCRY_PK_DSA
#define PUBKEY_ALGO_ECDH 18 /* corresponds to GCRY_PK_ECDH ECC DH; encrypt only */ #define PUBKEY_ALGO_ECDH 18
#define PUBKEY_ALGO_ECDSA 19 /* corresponds to GCRY_PK_ECDSA ECC DSA; sign only */ #define PUBKEY_ALGO_ECDSA 19
#define PUBKEY_ALGO_ELGAMAL /* 20 */ GCRY_PK_ELG /* Elgamal encr+sign */ #define PUBKEY_ALGO_ELGAMAL /* 20 */ GCRY_PK_ELG /* Elgamal encr+sign */
#define PUBKEY_USAGE_SIG GCRY_PK_USAGE_SIGN /* Good for signatures. */ #define PUBKEY_USAGE_SIG GCRY_PK_USAGE_SIGN /* Good for signatures. */

View File

@ -245,6 +245,7 @@ parse_key (const unsigned char *data, size_t datalen,
break; break;
case 18: /* ECDH */ case 18: /* ECDH */
npkey = 3; npkey = 3;
break;
case 19: /* ECDSA */ case 19: /* ECDSA */
npkey = 2; npkey = 2;
break; break;