mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
Integrating http://code.google.com/p/gnupg-ecc/source/detail?r=15 .
The following works: gpg2 --gen-key (ECC) gpg2 --list-keys gpg2 --list-packets ~/.gnupg/pubring.gpg gpg2 --list-packets <private key from http://sites.google.com/site/brainhub/pgpecckeys> ECDH doesn't work yet as the code must be re-written to adjust for gpg-agent refactoring.
This commit is contained in:
parent
7bbc07fde0
commit
e0972d3d96
@ -27,6 +27,7 @@
|
||||
#include "agent.h"
|
||||
#include "i18n.h"
|
||||
#include "cvt-openpgp.h"
|
||||
#include "../include/cipher.h" /* for PUBKEY_ALGO_ECDSA, PUBKEY_ALGO_ECDH */
|
||||
|
||||
|
||||
/* Helper to pass data via the callback to do_unprotect. */
|
||||
@ -49,7 +50,12 @@ struct try_do_unprotect_arg_s
|
||||
gcry_sexp_t *r_key;
|
||||
};
|
||||
|
||||
|
||||
/* TODO: it is also in misc, which is not linked with the agent */
|
||||
static int
|
||||
map_pk_openpgp_to_gcry (int algo)
|
||||
{
|
||||
return (algo==PUBKEY_ALGO_ECDSA ? GCRY_PK_ECDSA : (algo==PUBKEY_ALGO_ECDH ? GCRY_PK_ECDH : algo));
|
||||
}
|
||||
|
||||
/* Compute the keygrip from the public key and store it at GRIP. */
|
||||
static gpg_error_t
|
||||
@ -80,6 +86,12 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
|
||||
"(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
|
||||
break;
|
||||
|
||||
case GCRY_PK_ECDSA:
|
||||
case GCRY_PK_ECDH:
|
||||
err = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(ecc(c%m)(q%m)))", pkey[0], pkey[1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
break;
|
||||
@ -94,7 +106,9 @@ 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
|
||||
parameters into our s-expression based format. */
|
||||
parameters into our s-expression based format.
|
||||
pubkey_algo is a libgcrypt ID
|
||||
*/
|
||||
static gpg_error_t
|
||||
convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
|
||||
{
|
||||
@ -103,6 +117,8 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
|
||||
|
||||
*r_key = NULL;
|
||||
|
||||
pubkey_algo = map_pk_openpgp_to_gcry( pubkey_algo );
|
||||
|
||||
switch (pubkey_algo)
|
||||
{
|
||||
case GCRY_PK_DSA:
|
||||
@ -128,6 +144,18 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
|
||||
skey[5]);
|
||||
break;
|
||||
|
||||
case GCRY_PK_ECDSA:
|
||||
err = gcry_sexp_build (&s_skey, NULL,
|
||||
"(private-key(ecdsa(c%m)(q%m)(d%m)))",
|
||||
skey[0], skey[1], skey[2]);
|
||||
break;
|
||||
|
||||
case GCRY_PK_ECDH:
|
||||
err = gcry_sexp_build (&s_skey, NULL,
|
||||
"(private-key(ecdh(c%m)(q%m)(p%m)(d%m)))",
|
||||
skey[0], skey[1], skey[2], skey[3]);
|
||||
break;
|
||||
|
||||
default:
|
||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
break;
|
||||
@ -202,6 +230,10 @@ do_unprotect (const char *passphrase,
|
||||
|
||||
*r_key = NULL;
|
||||
|
||||
/* Unfortunately, the OpenPGP PK algorithm numbers need to be re-mapped for Libgcrypt
|
||||
*/
|
||||
pubkey_algo = map_pk_openpgp_to_gcry( pubkey_algo );
|
||||
|
||||
/* Count the actual number of MPIs is in the array and set the
|
||||
remainder to NULL for easier processing later on. */
|
||||
for (skeylen = 0; skey[skeylen]; skeylen++)
|
||||
@ -219,9 +251,6 @@ do_unprotect (const char *passphrase,
|
||||
|
||||
if (gcry_pk_test_algo (pubkey_algo))
|
||||
{
|
||||
/* The algorithm numbers are Libgcrypt numbers but fortunately
|
||||
the OpenPGP algorithm numbers map one-to-one to the Libgcrypt
|
||||
numbers. */
|
||||
log_info (_("public key algorithm %d (%s) is not supported\n"),
|
||||
pubkey_algo, gcry_pk_algo_name (pubkey_algo));
|
||||
return gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
@ -632,7 +661,7 @@ convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
|
||||
string = gcry_sexp_nth_string (list, 1);
|
||||
if (!string)
|
||||
goto bad_seckey;
|
||||
pubkey_algo = gcry_pk_map_name (string);
|
||||
pubkey_algo = gcry_pk_map_name (string); /* ligcrypt IDs */
|
||||
xfree (string);
|
||||
|
||||
if (gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
|
||||
@ -999,6 +1028,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
||||
}
|
||||
|
||||
algo = gcry_pk_map_name (name);
|
||||
log_debug ( "convert to openpgp begin for algo=%s\n", name );
|
||||
xfree (name);
|
||||
|
||||
switch (algo)
|
||||
@ -1007,7 +1037,8 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
||||
case GCRY_PK_ELG: algoname = "elg"; npkey = 3; elems = "pgyx"; break;
|
||||
case GCRY_PK_ELG_E: algoname = "elg"; npkey = 3; elems = "pgyx"; break;
|
||||
case GCRY_PK_DSA: algoname = "dsa"; npkey = 4; elems = "pqgyx"; break;
|
||||
case GCRY_PK_ECDSA: algoname = "ecdsa"; npkey = 6; elems = "pabgnqd"; break;
|
||||
case GCRY_PK_ECDSA: algoname = "ecdsa"; npkey = 2; elems = "cqd"; break;
|
||||
case GCRY_PK_ECDH: algoname = "ecdh"; npkey = 3; elems = "cqpd"; break;
|
||||
default: algoname = ""; npkey = 0; elems = NULL; break;
|
||||
}
|
||||
assert (!elems || strlen (elems) < DIM (array) );
|
||||
@ -1027,6 +1058,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
||||
err = apply_protection (array, npkey, nskey, passphrase,
|
||||
GCRY_CIPHER_AES, protect_iv, sizeof protect_iv,
|
||||
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
|
||||
return a protected key. */
|
||||
if (!err)
|
||||
@ -1037,7 +1069,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
||||
int format_args_buf_int[1];
|
||||
void *format_args[10+2];
|
||||
size_t n;
|
||||
gcry_sexp_t tmpkey, tmpsexp;
|
||||
gcry_sexp_t tmpkey, tmpsexp = NULL;
|
||||
|
||||
snprintf (countbuf, sizeof countbuf, "%lu", s2k_count);
|
||||
|
||||
@ -1056,6 +1088,8 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
||||
put_membuf_str (&mbuf, ")\n");
|
||||
put_membuf (&mbuf, "", 1);
|
||||
|
||||
///log_debug ( "convert to openpgp: calling gcry_sexp_build\n" );
|
||||
|
||||
tmpkey = NULL;
|
||||
{
|
||||
char *format = get_membuf (&mbuf, NULL);
|
||||
@ -1065,6 +1099,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
||||
err = gcry_sexp_build_array (&tmpkey, NULL, format, format_args);
|
||||
xfree (format);
|
||||
}
|
||||
///log_debug ( "convert to openpgp: calling gcry_sexp_build before err=%d\n", err );
|
||||
if (!err)
|
||||
err = gcry_sexp_build (&tmpsexp, NULL,
|
||||
"(openpgp-private-key\n"
|
||||
@ -1077,6 +1112,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
||||
(int)sizeof protect_iv, protect_iv,
|
||||
(int)sizeof salt, salt,
|
||||
countbuf);
|
||||
///log_debug ( "convert to openpgp: after gcry_sexp_build, err = %d\n", err );
|
||||
gcry_sexp_release (tmpkey);
|
||||
if (!err)
|
||||
err = make_canon_sexp_pad (tmpsexp, 0, r_transferkey, r_transferkeylen);
|
||||
@ -1085,6 +1121,8 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
||||
|
||||
for (i=0; i < DIM (array); i++)
|
||||
gcry_mpi_release (array[i]);
|
||||
|
||||
log_debug ( "convert to openpgp end with err=%d\n", err );
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -726,6 +726,16 @@ key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list,
|
||||
algoname = "dsa";
|
||||
elems = "pqgy";
|
||||
}
|
||||
else if (n==5 && !memcmp (name, "ecdsa", 5))
|
||||
{
|
||||
algoname = "ecdsa";
|
||||
elems = "cq";
|
||||
}
|
||||
else if (n==4 && !memcmp (name, "ecdh", 4))
|
||||
{
|
||||
algoname = "ecdh";
|
||||
elems = "cqp";
|
||||
}
|
||||
else if (n==3 && !memcmp (name, "elg", 3))
|
||||
{
|
||||
algoname = "elg";
|
||||
|
@ -52,6 +52,8 @@ static struct {
|
||||
{ "rsa", "nedpqu", 2, 5 },
|
||||
{ "dsa", "pqgyx", 4, 4 },
|
||||
{ "elg", "pgyx", 3, 3 },
|
||||
{ "ecdsa","cqd", 2, 2 },
|
||||
{ "ecdh", "cqpd", 3, 3 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -426,6 +428,9 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
|
||||
unsigned char *p;
|
||||
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. */
|
||||
memcpy (timestamp_exp, "(12:protected-at15:", 19);
|
||||
gnupg_get_isotime (timestamp_exp+19);
|
||||
@ -454,37 +459,51 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
|
||||
for (infidx=0; protect_info[infidx].algo
|
||||
&& !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);
|
||||
}
|
||||
|
||||
prot_begin = prot_end = NULL;
|
||||
for (i=0; (c=protect_info[infidx].parmlist[i]); i++)
|
||||
{
|
||||
if (i == protect_info[infidx].prot_from)
|
||||
prot_begin = s;
|
||||
if (*s != '(')
|
||||
if (*s != '(') {
|
||||
log_info ("Unbalanced bracket in S-expression #1\n");
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
}
|
||||
depth++;
|
||||
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);
|
||||
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);
|
||||
s += n;
|
||||
}
|
||||
s += n;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
if (!n) {
|
||||
log_info ("Invalid fieled in S-expression field\n");
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
}
|
||||
s +=n; /* skip value */
|
||||
if (*s != ')')
|
||||
if (*s != ')') {
|
||||
log_info ("Unbalanced bracket in S-expression #2\n");
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
}
|
||||
depth--;
|
||||
if (i == protect_info[infidx].prot_to)
|
||||
prot_end = 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);
|
||||
}
|
||||
depth--;
|
||||
hash_end = s;
|
||||
s++;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "gcrypt.h"
|
||||
|
||||
|
||||
#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
|
||||
@ -245,5 +246,31 @@ hex2str_alloc (const char *hexstring, size_t *r_count)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* returns hex representation of the MPI;
|
||||
* caller must free with xfree
|
||||
* Returns NULL on error, never throws
|
||||
*/
|
||||
char *mpi2hex( gcry_mpi_t m ) {
|
||||
size_t nbytes;
|
||||
size_t nbytes2;
|
||||
int rc;
|
||||
byte *p;
|
||||
|
||||
nbytes = (mpi_get_nbits ( m )+7)/8;
|
||||
if( nbytes == 0 )
|
||||
return NULL;
|
||||
p = xtrymalloc( nbytes*3+1 );
|
||||
if( p==NULL )
|
||||
return NULL;
|
||||
rc = gcry_mpi_print (GCRYMPI_FMT_USG, p+2*nbytes+1, nbytes, &nbytes2, m);
|
||||
if( rc ) {
|
||||
xfree( p );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bin2hex( p+2*nbytes+1, nbytes2, p );
|
||||
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);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -192,6 +192,7 @@ gpg_error_t get_pk_algo_from_canon_sexp (const unsigned char *keydata,
|
||||
int hex2bin (const char *string, void *buffer, size_t length);
|
||||
int hexcolon2bin (const char *string, void *buffer, size_t length);
|
||||
char *bin2hex (const void *buffer, size_t length, char *stringbuf);
|
||||
char *mpi2hex (gcry_mpi_t m);
|
||||
char *bin2hexcolon (const void *buffer, size_t length, char *stringbuf);
|
||||
const char *hex2str (const char *hexstring,
|
||||
char *buffer, size_t bufsize, size_t *buflen);
|
||||
|
@ -24,7 +24,7 @@ min_automake_version="1.10"
|
||||
# Remember to change the version number immediately *after* a release.
|
||||
# Set my_issvn to "yes" for non-released code. Remember to run an
|
||||
# "svn up" and "autogen.sh" right before creating a distribution.
|
||||
m4_define([my_version], [2.1.0])
|
||||
m4_define([my_version], [2.2.0])
|
||||
m4_define([my_issvn], [yes])
|
||||
|
||||
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_LIBGCRYPT_API=1
|
||||
NEED_LIBGCRYPT_VERSION=1.4.0
|
||||
NEED_LIBGCRYPT_VERSION=1.6.0
|
||||
|
||||
NEED_LIBASSUAN_API=2
|
||||
NEED_LIBASSUAN_VERSION=2.0.0
|
||||
@ -1466,7 +1466,7 @@ AC_ARG_ENABLE(optimization,
|
||||
AC_HELP_STRING([--disable-optimization],
|
||||
[disable compiler optimization]),
|
||||
[if test $enableval = no ; then
|
||||
CFLAGS=`echo $CFLAGS | sed s/-O[[1-9]]\ /-O0\ /g`
|
||||
CFLAGS=`echo $CFLAGS | sed s%-O[[1-9]]%-O0\ %g`
|
||||
fi])
|
||||
|
||||
#
|
||||
|
@ -61,7 +61,7 @@ endif
|
||||
dirmngr_LDADD = $(libcommonpth) ../gl/libgnu.a $(DNSLIBS) $(LIBASSUAN_LIBS) \
|
||||
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(PTH_LIBS) $(LIBINTL) $(LIBICONV)
|
||||
if !USE_LDAPWRAPPER
|
||||
dirmngr_LDADD += $(LDAPLIBS)
|
||||
dirmngr_LDADD += $(LDAPLIBS) -llber
|
||||
endif
|
||||
dirmngr_LDFLAGS = $(extra_bin_ldflags)
|
||||
|
||||
|
@ -72,7 +72,8 @@ common_source = \
|
||||
plaintext.c \
|
||||
sig-check.c \
|
||||
keylist.c \
|
||||
pkglue.c pkglue.h
|
||||
pkglue.c pkglue.h \
|
||||
ecdh.c
|
||||
|
||||
gpg2_SOURCES = gpg.c \
|
||||
server.c \
|
||||
@ -109,7 +110,8 @@ gpg2_SOURCES = gpg.c \
|
||||
|
||||
gpgv2_SOURCES = gpgv.c \
|
||||
$(common_source) \
|
||||
verify.c
|
||||
verify.c \
|
||||
verify-stubs.c
|
||||
|
||||
#gpgd_SOURCES = gpgd.c \
|
||||
# ks-proto.h \
|
||||
|
@ -1079,7 +1079,7 @@ armor_filter( void *opaque, int control,
|
||||
iobuf_writestr(a,afx->eol);
|
||||
if( !opt.no_version )
|
||||
{
|
||||
iobuf_writestr(a, "Version: GnuPG v" VERSION " ("
|
||||
iobuf_writestr(a, "Version: GnuPG v" VERSION "-ecc ("
|
||||
PRINTABLE_OS_NAME ")" );
|
||||
iobuf_writestr(a,afx->eol);
|
||||
}
|
||||
|
@ -178,6 +178,16 @@ mpi_write (iobuf_t out, gcry_mpi_t a)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the name OID, encoded as an mpi, to OUT. The format of the content of the MPI is
|
||||
* one byte LEN, following by LEN bytes that are DER representation of an ASN.1 OID.
|
||||
* This is true for each of the 3 following functions.
|
||||
*/
|
||||
#define iobuf_name_oid_write iobuf_write_size_body_mpi
|
||||
/* Write the value of KEK fields for ECDH. */
|
||||
#define ecdh_kek_params_write iobuf_write_size_body_mpi
|
||||
/* Write the value of encrypted filed for ECDH. */
|
||||
#define ecdh_esk_write iobuf_write_size_body_mpi
|
||||
|
||||
|
||||
/****************
|
||||
@ -290,10 +300,24 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|
||||
}
|
||||
assert (npkey < nskey);
|
||||
|
||||
/* Writing the public parameters is easy. */
|
||||
for (i=0; i < npkey; i++ )
|
||||
if ((err = mpi_write (a, pk->pkey[i])))
|
||||
goto leave;
|
||||
if( pk->pubkey_algo != PUBKEY_ALGO_ECDSA && pk->pubkey_algo != PUBKEY_ALGO_ECDH ) {
|
||||
/* Writing the public parameters is easy, */
|
||||
for (i=0; i < npkey; i++ )
|
||||
if ((err = mpi_write (a, pk->pkey[i])))
|
||||
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;
|
||||
}
|
||||
if( pk->pubkey_algo == PUBKEY_ALGO_ECDH && (err=ecdh_kek_params_write(a,pk->pkey[2]))) { /* one more public field for ECDH */
|
||||
goto leave;
|
||||
}
|
||||
/* followed by possibly protected private scalar */
|
||||
}
|
||||
|
||||
if (pk->seckey_info)
|
||||
{
|
||||
@ -458,8 +482,18 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
|
||||
n = pubkey_get_nenc( enc->pubkey_algo );
|
||||
if ( !n )
|
||||
write_fake_data( a, enc->data[0] );
|
||||
for (i=0; i < n && !rc ; i++ )
|
||||
rc = mpi_write(a, enc->data[i] );
|
||||
|
||||
if( enc->pubkey_algo != PUBKEY_ALGO_ECDH ) {
|
||||
for (i=0; i < n && !rc ; i++ )
|
||||
rc = mpi_write(a, enc->data[i] );
|
||||
}
|
||||
else {
|
||||
/* the second field persists as a LEN+field structure, even though it is
|
||||
* stored for uniformity as an MPI internally */
|
||||
assert( n==2 );
|
||||
rc = mpi_write(a, enc->data[0] );
|
||||
if( !rc ) rc = ecdh_esk_write(a, enc->data[1] );
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
|
@ -1744,6 +1744,7 @@ inq_ciphertext_cb (void *opaque, const char *line)
|
||||
gpg_error_t
|
||||
agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
|
||||
gcry_sexp_t s_ciphertext,
|
||||
const byte sk_fp[MAX_FINGERPRINT_LEN],
|
||||
unsigned char **r_buf, size_t *r_buflen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
@ -1751,6 +1752,8 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
|
||||
membuf_t data;
|
||||
size_t n, len;
|
||||
char *p, *buf, *endp;
|
||||
|
||||
/*TODO: use sk_fp */
|
||||
|
||||
if (!keygrip || strlen(keygrip) != 40 || !s_ciphertext || !r_buf || !r_buflen)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
@ -168,6 +168,7 @@ gpg_error_t agent_pksign (ctrl_t ctrl, const char *cache_nonce,
|
||||
/* Decrypt a ciphertext. */
|
||||
gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
|
||||
gcry_sexp_t s_ciphertext,
|
||||
const byte sk_fp[MAX_FINGERPRINT_LEN],
|
||||
unsigned char **r_buf, size_t *r_buflen);
|
||||
|
||||
/* Retrieve a key encryption key. */
|
||||
|
477
g10/ecdh.c
Normal file
477
g10/ecdh.c
Normal file
@ -0,0 +1,477 @@
|
||||
/* ecdh.c - ECDH public key operations used in public key glue code
|
||||
* Copyright (C) 2000, 2003 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "gpg.h"
|
||||
#include "util.h"
|
||||
#include "pkglue.h"
|
||||
#include "main.h"
|
||||
#include "options.h"
|
||||
|
||||
gcry_mpi_t
|
||||
pk_ecdh_default_params_to_mpi( int qbits ) {
|
||||
gpg_error_t err;
|
||||
gcry_mpi_t result;
|
||||
/* Defaults are the strongest possible choices. Performance is not an issue here, only interoperability. */
|
||||
byte kek_params[4] = {
|
||||
3 /*size of following field*/,
|
||||
1 /*fixed version for KDF+AESWRAP*/,
|
||||
DIGEST_ALGO_SHA512 /* KEK MD */,
|
||||
CIPHER_ALGO_AES256 /*KEK AESWRAP alg*/
|
||||
};
|
||||
int i;
|
||||
|
||||
static const struct {
|
||||
int qbits;
|
||||
int openpgp_hash_id;
|
||||
int openpgp_cipher_id;
|
||||
} kek_params_table[] = {
|
||||
{ 256, DIGEST_ALGO_SHA256, CIPHER_ALGO_AES },
|
||||
{ 384, DIGEST_ALGO_SHA384, CIPHER_ALGO_AES256 },
|
||||
{ 528, DIGEST_ALGO_SHA512, CIPHER_ALGO_AES256 } // 528 is 521 rounded to the 8 bit boundary
|
||||
};
|
||||
|
||||
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;
|
||||
kek_params[3] = kek_params_table[i].openpgp_cipher_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( DBG_CIPHER )
|
||||
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);
|
||||
if (err)
|
||||
log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* returns allocated (binary) KEK parameters; the size is returned in sizeout.
|
||||
* The caller must free returned value with xfree.
|
||||
* Returns NULL on error
|
||||
*/
|
||||
byte *
|
||||
pk_ecdh_default_params( int qbits, size_t *sizeout ) {
|
||||
gpg_error_t err;
|
||||
gcry_mpi_t result;
|
||||
/* Defaults are the strongest possible choices. Performance is not an issue here, only interoperability. */
|
||||
byte kek_params[4] = {
|
||||
3 /*size of following field*/,
|
||||
1 /*fixed version for KDF+AESWRAP*/,
|
||||
DIGEST_ALGO_SHA512 /* KEK MD */,
|
||||
CIPHER_ALGO_AES256 /*KEK AESWRAP alg*/
|
||||
};
|
||||
int i;
|
||||
|
||||
static const struct {
|
||||
int qbits;
|
||||
int openpgp_hash_id;
|
||||
int openpgp_cipher_id;
|
||||
} kek_params_table[] = {
|
||||
{ 256, DIGEST_ALGO_SHA256, CIPHER_ALGO_AES },
|
||||
{ 384, DIGEST_ALGO_SHA384, CIPHER_ALGO_AES256 },
|
||||
{ 528, DIGEST_ALGO_SHA512, CIPHER_ALGO_AES256 } // 528 is 521 rounded to the 8 bit boundary
|
||||
};
|
||||
|
||||
byte *p;
|
||||
|
||||
*sizeout = 0;
|
||||
|
||||
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;
|
||||
kek_params[3] = kek_params_table[i].openpgp_cipher_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( DBG_CIPHER )
|
||||
log_printhex ("ecdh kek params are", kek_params, sizeof(kek_params) );
|
||||
|
||||
p = xtrymalloc( sizeof(kek_params) );
|
||||
if( p == NULL )
|
||||
return NULL;
|
||||
memcpy( p, kek_params, sizeof(kek_params) );
|
||||
*sizeout = sizeof(kek_params);
|
||||
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).
|
||||
* The result is returned in out as a size+value MPI.
|
||||
* TODO: memory leaks (x_secret).
|
||||
*/
|
||||
static int
|
||||
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)
|
||||
{
|
||||
byte *secret_x;
|
||||
int secret_x_size;
|
||||
byte kdf_params[256];
|
||||
int kdf_params_size=0;
|
||||
int nbits;
|
||||
int kdf_hash_algo;
|
||||
int kdf_encr_algo;
|
||||
int rc;
|
||||
|
||||
*out = NULL;
|
||||
|
||||
nbits = pubkey_nbits( PUBKEY_ALGO_ECDH, pkey );
|
||||
|
||||
{
|
||||
size_t nbytes;
|
||||
/* extract x component of the shared point: this is the actual shared secret */
|
||||
nbytes = (mpi_get_nbits (pkey[1] /* public point */)+7)/8;
|
||||
secret_x = xmalloc_secure( nbytes );
|
||||
rc = gcry_mpi_print (GCRYMPI_FMT_USG, secret_x, nbytes, &nbytes, shared_mpi);
|
||||
if( 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;
|
||||
assert( nbytes > secret_x_size );
|
||||
memmove( secret_x, secret_x+1, secret_x_size );
|
||||
memset( secret_x+secret_x_size, 0, nbytes-secret_x_size );
|
||||
|
||||
if( DBG_CIPHER )
|
||||
log_printhex ("ecdh shared secret X is:", secret_x, secret_x_size );
|
||||
}
|
||||
|
||||
/*** 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
|
||||
* key encryption techniques to protect the 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();
|
||||
rc = iobuf_write_size_body_mpi ( obuf, pkey[2] ); /* KEK 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( 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;
|
||||
|
||||
kdf_hash_algo = kdf_params[2];
|
||||
kdf_encr_algo = kdf_params[3];
|
||||
|
||||
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) );
|
||||
|
||||
if( kdf_hash_algo != GCRY_MD_SHA256 && kdf_hash_algo != GCRY_MD_SHA384 && kdf_hash_algo != GCRY_MD_SHA512 )
|
||||
return GPG_ERR_BAD_PUBKEY;
|
||||
if( kdf_encr_algo != GCRY_CIPHER_AES128 && kdf_encr_algo != GCRY_CIPHER_AES192 && kdf_encr_algo != GCRY_CIPHER_AES256 )
|
||||
return GPG_ERR_BAD_PUBKEY;
|
||||
}
|
||||
|
||||
/* build kdf_params */
|
||||
{
|
||||
IOBUF obuf;
|
||||
|
||||
obuf = iobuf_temp();
|
||||
/* variable-length field 1, curve name OID */
|
||||
rc = iobuf_write_size_body_mpi ( obuf, pkey[0] );
|
||||
/* fixed-length field 2 */
|
||||
iobuf_put (obuf, PUBKEY_ALGO_ECDH);
|
||||
/* variable-length field 3, KDF params */
|
||||
rc = (rc ? rc : iobuf_write_size_body_mpi ( obuf, pkey[2] ));
|
||||
/* fixed-length field 4 */
|
||||
iobuf_write (obuf, "Anonymous Sender ", 20);
|
||||
/* fixed-length field 5, recipient fp */
|
||||
iobuf_write (obuf, pk_fp, 20);
|
||||
|
||||
kdf_params_size = iobuf_temp_to_buffer( obuf, kdf_params, sizeof(kdf_params) );
|
||||
iobuf_close( obuf );
|
||||
if( rc ) {
|
||||
return rc;
|
||||
}
|
||||
if( DBG_CIPHER )
|
||||
log_printhex ("ecdh KDF message params are:", kdf_params, kdf_params_size );
|
||||
}
|
||||
|
||||
/* Derive a KEK (key wrapping key) using kdf_params and secret_x. */
|
||||
{
|
||||
gcry_md_hd_t h;
|
||||
int old_size;
|
||||
|
||||
rc = gcry_md_open (&h, kdf_hash_algo, 0);
|
||||
if(rc)
|
||||
log_bug ("gcry_md_open failed for algo %d: %s",
|
||||
kdf_hash_algo, gpg_strerror (gcry_error(rc)));
|
||||
gcry_md_write(h, "\x00\x00\x00\x01", 4); /* counter = 1 */
|
||||
gcry_md_write(h, secret_x, secret_x_size); /* x of the point X */
|
||||
gcry_md_write(h, kdf_params, kdf_params_size); /* KDF parameters */
|
||||
|
||||
gcry_md_final (h);
|
||||
|
||||
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));
|
||||
gcry_md_close (h);
|
||||
|
||||
old_size = secret_x_size;
|
||||
assert( old_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) );
|
||||
|
||||
memset( secret_x+secret_x_size, old_size-secret_x_size, 0 ); /* we could have allocated more, so clean the tail before returning */
|
||||
if( DBG_CIPHER )
|
||||
log_printhex ("ecdh KEK is:", secret_x, secret_x_size );
|
||||
}
|
||||
|
||||
/* And, finally, aeswrap with key secret_x */
|
||||
{
|
||||
gcry_cipher_hd_t hd;
|
||||
size_t nbytes;
|
||||
|
||||
byte *data_buf;
|
||||
int data_buf_size;
|
||||
|
||||
gcry_mpi_t result;
|
||||
|
||||
rc = gcry_cipher_open (&hd, kdf_encr_algo, GCRY_CIPHER_MODE_AESWRAP, 0);
|
||||
if (rc)
|
||||
{
|
||||
log_error( "ecdh failed to initialize AESWRAP: %s\n", gpg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = gcry_cipher_setkey (hd, secret_x, secret_x_size);
|
||||
xfree( secret_x );
|
||||
if (rc)
|
||||
{
|
||||
gcry_cipher_close (hd);
|
||||
log_error("ecdh failed in gcry_cipher_setkey: %s\n", gpg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
data_buf_size = (gcry_mpi_get_nbits(data)+7)/8;
|
||||
assert( (data_buf_size & 7) == (is_encrypt ? 0 : 1) );
|
||||
|
||||
data_buf = xmalloc_secure( 1 + 2*data_buf_size + 8 );
|
||||
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));
|
||||
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] );
|
||||
|
||||
rc = gcry_mpi_scan ( &result, GCRYMPI_FMT_USG, data_buf, 1+data_buf[0], NULL); /* (byte)size + aeswrap of DEK */
|
||||
xfree( data_buf );
|
||||
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;
|
||||
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 );
|
||||
gcry_cipher_close (hd);
|
||||
if(rc)
|
||||
{
|
||||
log_error("ecdh failed in gcry_cipher_decrypt: %s\n", gpg_strerror (rc));
|
||||
xfree( data_buf );
|
||||
return rc;
|
||||
}
|
||||
|
||||
data_buf_size-=8;
|
||||
|
||||
if( DBG_CIPHER )
|
||||
log_printhex ("ecdh decrypted to :", in, data_buf_size );
|
||||
|
||||
/* padding is removed later */
|
||||
//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;
|
||||
//}
|
||||
|
||||
rc = gcry_mpi_scan ( &result, GCRYMPI_FMT_USG, in, data_buf_size, NULL);
|
||||
xfree( data_buf );
|
||||
if(rc)
|
||||
{
|
||||
log_error("ecdh failed to create a plain text MPI: %s\n", gpg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
*out = result;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Perform ECDH encryption, which involves ECDH key generation.
|
||||
*/
|
||||
int
|
||||
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;
|
||||
|
||||
PKT_public_key *pk_eph;
|
||||
int nbits;
|
||||
int rc;
|
||||
|
||||
nbits = pubkey_nbits( PUBKEY_ALGO_ECDH, pkey );
|
||||
|
||||
/*** Generate an ephemeral key ***/
|
||||
|
||||
rc = pk_ecc_keypair_gen( &pk_eph, PUBKEY_ALGO_ECDH, KEYGEN_FLAG_TRANSIENT_KEY | KEYGEN_FLAG_NO_PROTECTION /*this is ephemeral*/, "", nbits );
|
||||
if( rc )
|
||||
return rc;
|
||||
if( DBG_CIPHER ) {
|
||||
unsigned char *buffer;
|
||||
if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, pk_eph->pkey[1]))
|
||||
BUG ();
|
||||
log_debug("ephemeral key MPI #0: %s\n", buffer);
|
||||
gcry_free( buffer );
|
||||
}
|
||||
free_public_key (pk_eph);
|
||||
|
||||
/*** Done with ephemeral key generation.
|
||||
* Now use ephemeral secret to get the shared secret. ***/
|
||||
|
||||
rc = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(ecdh(c%m)(q%m)(p%m)))", pkey[0], pkey[1], pkey[2]);
|
||||
if (rc)
|
||||
BUG ();
|
||||
|
||||
/* put the data into a simple list */
|
||||
if (gcry_sexp_build (&s_data, NULL, "%m", pk_eph->pkey[3])) /* ephemeral scalar goes as data */
|
||||
BUG ();
|
||||
|
||||
/* pass it to libgcrypt */
|
||||
rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
|
||||
gcry_sexp_release (s_data);
|
||||
gcry_sexp_release (s_pkey);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* finally, perform encryption */
|
||||
|
||||
{
|
||||
gcry_mpi_t shared = mpi_from_sexp (s_ciph, "a"); /* ... and get the shared point */
|
||||
gcry_sexp_release (s_ciph);
|
||||
resarr[0] = pk_eph->pkey[1]; /* ephemeral public key */
|
||||
|
||||
if( DBG_CIPHER ) {
|
||||
unsigned char *buffer;
|
||||
if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, resarr[0]))
|
||||
BUG ();
|
||||
log_debug("ephemeral key MPI: %s\n", buffer);
|
||||
gcry_free( buffer );
|
||||
}
|
||||
|
||||
rc = pk_ecdh_encrypt_with_shared_point ( 1 /*=encrypton*/, shared, pk_fp, data, pkey, resarr+1 );
|
||||
mpi_release( shared );
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Perform ECDH decryption.
|
||||
*/
|
||||
int
|
||||
pk_ecdh_decrypt (gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t *data, gcry_mpi_t * skey) {
|
||||
gcry_sexp_t s_skey, s_data, s_ciph;
|
||||
int rc;
|
||||
|
||||
if (!data[0] || !data[1])
|
||||
return gpg_error (GPG_ERR_BAD_MPI);
|
||||
|
||||
rc = gcry_sexp_build (&s_skey, NULL,
|
||||
"(public-key(ecdh(c%m)(q%m)(p%m)))",
|
||||
skey[0]/*curve*/, data[0]/*ephemeral key*/, skey[2]/*KDF params*/);
|
||||
if (rc)
|
||||
BUG ();
|
||||
|
||||
/* put the data into a simple list */
|
||||
if (gcry_sexp_build (&s_data, NULL, "%m", skey[3])) /* static private key (scalar) goes as data */
|
||||
BUG ();
|
||||
|
||||
rc = gcry_pk_encrypt (&s_ciph, s_data, s_skey); /* encrypting ephemeral key with our private scalar yields the shared point */
|
||||
gcry_sexp_release (s_skey);
|
||||
gcry_sexp_release (s_data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
{
|
||||
gcry_mpi_t shared = mpi_from_sexp (s_ciph, "a"); /* get the shared point */
|
||||
gcry_sexp_release (s_ciph);
|
||||
rc = pk_ecdh_encrypt_with_shared_point ( 0 /*=decryption*/, shared, sk_fp, data[1]/*encr data as an MPI*/, skey, result );
|
||||
mpi_release( shared );
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -876,7 +876,9 @@ write_pubkey_enc_from_list (PK_LIST pk_list, DEK *dek, iobuf_t out)
|
||||
for ( ; pk_list; pk_list = pk_list->next )
|
||||
{
|
||||
gcry_mpi_t frame;
|
||||
|
||||
byte fp[MAX_FINGERPRINT_LEN];
|
||||
size_t fpn;
|
||||
|
||||
pk = pk_list->pk;
|
||||
|
||||
print_pubkey_algo_note ( pk->pubkey_algo );
|
||||
@ -892,6 +894,9 @@ write_pubkey_enc_from_list (PK_LIST pk_list, DEK *dek, iobuf_t out)
|
||||
compliance_failure();
|
||||
}
|
||||
|
||||
fingerprint_from_pk( pk, fp, &fpn );
|
||||
assert( fpn == 20 );
|
||||
|
||||
/* Okay, what's going on: We have the session key somewhere in
|
||||
* the structure DEK and want to encode this session key in an
|
||||
* integer value of n bits. pubkey_nbits gives us the number of
|
||||
@ -904,9 +909,9 @@ write_pubkey_enc_from_list (PK_LIST pk_list, DEK *dek, iobuf_t out)
|
||||
* for Elgamal). We don't need frame anymore because we have
|
||||
* everything now in enc->data which is the passed to
|
||||
* build_packet(). */
|
||||
frame = encode_session_key (dek,
|
||||
frame = encode_session_key (pk->pubkey_algo, dek,
|
||||
pubkey_nbits (pk->pubkey_algo, pk->pkey));
|
||||
rc = pk_encrypt (pk->pubkey_algo, enc->data, frame, pk->pkey);
|
||||
rc = pk_encrypt (pk->pubkey_algo, enc->data, frame, fp, pk->pkey);
|
||||
gcry_mpi_release (frame);
|
||||
if (rc)
|
||||
log_error ("pubkey_encrypt failed: %s\n", gpg_strerror (rc) );
|
||||
|
12
g10/export.c
12
g10/export.c
@ -1161,6 +1161,18 @@ build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent)
|
||||
/* iobuf_put (out,')'); iobuf_put (out,'\n'); */
|
||||
/* (*indent)--; */
|
||||
/* } */
|
||||
/*
|
||||
else if (sk->pubkey_algo == PUBKEY_ALGO_ECDSA && !sk->is_protected)
|
||||
{
|
||||
write_sexp_line (out, indent, "(ecdsa\n");
|
||||
(*indent)++;
|
||||
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, "d", sk->skey[7]);
|
||||
iobuf_put (out,')'); iobuf_put (out,'\n');
|
||||
(*indent)--;
|
||||
}
|
||||
*/
|
||||
/* else if (is_ELGAMAL (sk->pubkey_algo) && !sk->is_protected) */
|
||||
/* { */
|
||||
/* write_sexp_line (out, indent, "(elg\n"); */
|
||||
|
@ -138,7 +138,10 @@ cache_public_key (PKT_public_key * pk)
|
||||
return;
|
||||
|
||||
if (is_ELGAMAL (pk->pubkey_algo)
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_DSA || is_RSA (pk->pubkey_algo))
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_DSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH
|
||||
|| is_RSA (pk->pubkey_algo))
|
||||
{
|
||||
keyid_from_pk (pk, keyid);
|
||||
}
|
||||
|
@ -813,7 +813,7 @@ my_strusage( int level )
|
||||
const char *p;
|
||||
|
||||
switch( level ) {
|
||||
case 11: p = "gpg (GnuPG)";
|
||||
case 11: p = "gpg (GnuPG) ecc";
|
||||
break;
|
||||
case 13: p = VERSION; break;
|
||||
case 17: p = PRINTABLE_OS_NAME; break;
|
||||
@ -857,7 +857,7 @@ my_strusage( int level )
|
||||
case 34:
|
||||
if (!pubkeys)
|
||||
pubkeys = build_list (_("Pubkey: "), 0,
|
||||
gcry_pk_algo_name,
|
||||
openpgp_pk_algo_name,
|
||||
openpgp_pk_test_algo );
|
||||
p = pubkeys;
|
||||
break;
|
||||
|
281
g10/keygen.c
281
g10/keygen.c
@ -42,6 +42,8 @@
|
||||
#include "i18n.h"
|
||||
#include "keyserver-internal.h"
|
||||
#include "call-agent.h"
|
||||
#include "pkglue.h"
|
||||
#include "gcrypt.h"
|
||||
|
||||
/* The default algorithms. If you change them remember to change them
|
||||
also in gpg.c:gpgconf_list. You should also check that the value
|
||||
@ -49,10 +51,6 @@
|
||||
#define DEFAULT_STD_ALGO GCRY_PK_RSA
|
||||
#define DEFAULT_STD_KEYSIZE 2048
|
||||
|
||||
#define KEYGEN_FLAG_NO_PROTECTION 1
|
||||
#define KEYGEN_FLAG_TRANSIENT_KEY 2
|
||||
|
||||
|
||||
#define MAX_PREFS 30
|
||||
|
||||
enum para_name {
|
||||
@ -1130,17 +1128,15 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Common code for the key generation fucntion gen_xxx. */
|
||||
static int
|
||||
common_gen (const char *keyparms, int algo, const char *algoelem,
|
||||
kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey,
|
||||
int keygen_flags, char **cache_nonce_addr)
|
||||
common_key_gen (const char *keyparms, int algo, const char *algoelem,
|
||||
int keygen_flags, char **cache_nonce_addr, PKT_public_key **pk_out)
|
||||
{
|
||||
int err;
|
||||
PACKET *pkt;
|
||||
PKT_public_key *pk;
|
||||
gcry_sexp_t s_key;
|
||||
|
||||
*pk_out = NULL;
|
||||
|
||||
err = agent_genkey (NULL, cache_nonce_addr, keyparms,
|
||||
!!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION), &s_key);
|
||||
@ -1158,10 +1154,7 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
|
||||
return err;
|
||||
}
|
||||
|
||||
pk->timestamp = timestamp;
|
||||
pk->version = 4;
|
||||
if (expireval)
|
||||
pk->expiredate = pk->timestamp + expireval;
|
||||
pk->pubkey_algo = algo;
|
||||
|
||||
err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
|
||||
@ -1174,21 +1167,45 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
|
||||
}
|
||||
gcry_sexp_release (s_key);
|
||||
|
||||
pkt = xtrycalloc (1, sizeof *pkt);
|
||||
if (!pkt)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
free_public_key (pk);
|
||||
return err;
|
||||
}
|
||||
|
||||
pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
|
||||
pkt->pkt.public_key = pk;
|
||||
add_kbnode (pub_root, new_kbnode (pkt));
|
||||
*pk_out = pk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Common code for the key generation fucntion gen_xxx. */
|
||||
static int
|
||||
common_gen (const char *keyparms, int algo, const char *algoelem,
|
||||
kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey,
|
||||
int keygen_flags, char **cache_nonce_addr)
|
||||
{
|
||||
PKT_public_key *pk;
|
||||
int err;
|
||||
|
||||
err = common_key_gen( keyparms, algo, algoelem, keygen_flags, cache_nonce_addr, &pk );
|
||||
|
||||
if( !err ) {
|
||||
PACKET *pkt;
|
||||
|
||||
pk->timestamp = timestamp;
|
||||
if (expireval)
|
||||
pk->expiredate = pk->timestamp + expireval;
|
||||
|
||||
pkt = xtrycalloc (1, sizeof *pkt);
|
||||
if (!pkt)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
free_public_key (pk);
|
||||
return err;
|
||||
}
|
||||
|
||||
pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
|
||||
pkt->pkt.public_key = pk;
|
||||
|
||||
add_kbnode (pub_root, new_kbnode (pkt));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate an Elgamal key.
|
||||
@ -1326,6 +1343,186 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Returns allocated ECC key generation S-explression
|
||||
call gcry_sexp_release ( out ) to free it.
|
||||
*/
|
||||
static int
|
||||
delme__pk_ecc_build_sexp( int qbits, int algo, int is_long_term, gcry_sexp_t *out ) {
|
||||
gcry_mpi_t kek_params;
|
||||
char *kek_params_s;
|
||||
int rc;
|
||||
|
||||
if( is_long_term && algo == PUBKEY_ALGO_ECDH )
|
||||
kek_params = pk_ecdh_default_params_to_mpi( qbits );
|
||||
else
|
||||
kek_params = NULL;
|
||||
|
||||
if( kek_params ) {
|
||||
kek_params_s = mpi2hex( kek_params );
|
||||
mpi_release( kek_params );
|
||||
}
|
||||
|
||||
rc = gcry_sexp_build (out, NULL,
|
||||
algo == PUBKEY_ALGO_ECDSA ?
|
||||
"(genkey(ecdsa(nbits %d)(qbits %d)))" :
|
||||
"(genkey(ecdh(nbits %d)(qbits %d)(transient-key %d)(kek-params %s)))",
|
||||
(int)qbits, (int)qbits, (int)(is_long_term==0), kek_params_s);
|
||||
xfree( kek_params_s );
|
||||
if (rc) {
|
||||
log_debug("ec gen gcry_sexp_build failed: %s\n", gpg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
pk_ecc_build_key_params( int qbits, int algo, int transient ) {
|
||||
byte *kek_params = NULL;
|
||||
size_t kek_params_size;
|
||||
char nbitsstr[35];
|
||||
char qbitsstr[35];
|
||||
char *keyparms;
|
||||
int n;
|
||||
|
||||
/* KEK parameters are only needed for long term key generation */
|
||||
if( !transient && algo == PUBKEY_ALGO_ECDH )
|
||||
kek_params = pk_ecdh_default_params( qbits, &kek_params_size );
|
||||
else
|
||||
kek_params = NULL;
|
||||
|
||||
snprintf (nbitsstr, sizeof nbitsstr, "%u", qbits);
|
||||
snprintf (qbitsstr, sizeof qbitsstr, "%u", qbits);
|
||||
if( algo == PUBKEY_ALGO_ECDSA || kek_params == NULL )
|
||||
keyparms = xtryasprintf (
|
||||
"(genkey(%s(nbits %zu:%s)(qbits %zu:%s)(transient-key 1:%d)))",
|
||||
algo == PUBKEY_ALGO_ECDSA ? "ecdsa" : "ecdh",
|
||||
strlen (nbitsstr), nbitsstr,
|
||||
strlen (qbitsstr), qbitsstr,
|
||||
transient );
|
||||
else {
|
||||
assert( kek_params != NULL );
|
||||
keyparms = xtryasprintf (
|
||||
"(genkey(ecdh(nbits %zu:%s)(qbits %zu:%s)(transient-key 1:%d)(kek-params %u:",
|
||||
strlen (nbitsstr), nbitsstr,
|
||||
strlen (qbitsstr), qbitsstr,
|
||||
transient,
|
||||
(unsigned)kek_params_size );
|
||||
if( keyparms != NULL ) {
|
||||
n = strlen(keyparms);
|
||||
keyparms = xtryrealloc( keyparms, n + kek_params_size + 4 );
|
||||
}
|
||||
if( keyparms == NULL ) {
|
||||
xfree( kek_params );
|
||||
return NULL;
|
||||
}
|
||||
memcpy( keyparms+n, kek_params, kek_params_size );
|
||||
xfree( kek_params );
|
||||
memcpy( keyparms+n+kek_params_size, ")))", 4 );
|
||||
}
|
||||
return keyparms;
|
||||
}
|
||||
|
||||
/* This common function is used in this file and also to generate ephemeral keys for ECDH.
|
||||
* Caller must call free_public_key and free_secret_key */
|
||||
int
|
||||
pk_ecc_keypair_gen( PKT_public_key **pk_out, int algo, int keygen_flags, char **cache_nonce_addr, unsigned nbits) {
|
||||
int err;
|
||||
unsigned int qbits;
|
||||
char *keyparms;
|
||||
// PUBKEY_ALGO_ECDH, PUBKEY_ALGO_ECDSA
|
||||
static const char * const ec_pub_params[2] = { "cqp", "cq" };
|
||||
//static const char * const ec_priv_params[2] = { "cqpd", "cqd" };
|
||||
|
||||
assert( algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH );
|
||||
assert( PUBKEY_ALGO_ECDSA == PUBKEY_ALGO_ECDH + 1 );
|
||||
|
||||
*pk_out = NULL;
|
||||
|
||||
if( pubkey_get_npkey (PUBKEY_ALGO_ECDSA) != 2 || pubkey_get_nskey (PUBKEY_ALGO_ECDSA) != 3 ||
|
||||
pubkey_get_npkey (PUBKEY_ALGO_ECDH) != 3 || pubkey_get_nskey (PUBKEY_ALGO_ECDH) != 4 )
|
||||
{
|
||||
log_info(_("incompatible version of gcrypt library (expect named curve logic for ECC)\n") );
|
||||
return GPG_ERR_EPROGMISMATCH;
|
||||
}
|
||||
|
||||
if ( nbits != 256 && nbits != 384 && nbits != 521 )
|
||||
{
|
||||
log_info(_("keysize invalid; using 256 bits instead of passed in %d\n"), nbits );
|
||||
}
|
||||
|
||||
/*
|
||||
Figure out a q size based on the key size. See gen_dsa for more details.
|
||||
Due to 8-bit rounding we may get 528 here instead of 521
|
||||
*/
|
||||
nbits = qbits = (nbits < 521 ? nbits : 521 );
|
||||
|
||||
keyparms = pk_ecc_build_key_params(qbits, algo, !!((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION)) );
|
||||
if (!keyparms) {
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("ec pk_ecc_build_key_params failed: %s\n", gpg_strerror (err) );
|
||||
}
|
||||
else
|
||||
{
|
||||
err = common_key_gen (keyparms, algo, ec_pub_params[algo-PUBKEY_ALGO_ECDH],
|
||||
keygen_flags, cache_nonce_addr, pk_out);
|
||||
xfree (keyparms);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* always allocase seckey_info for EC keys. TODO: is this needed? */
|
||||
if( *pk_out ) {
|
||||
struct seckey_info *ski;
|
||||
|
||||
(*pk_out)->seckey_info = ski = xtrycalloc (1, sizeof *ski);
|
||||
if (!(*pk_out)->seckey_info) {
|
||||
free_public_key(*pk_out);
|
||||
*pk_out = NULL;
|
||||
return gpg_error_from_syserror ();
|
||||
}
|
||||
|
||||
ski->is_protected = 0;
|
||||
ski->algo = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Generate an ECC OpenPGP key
|
||||
*/
|
||||
static gpg_error_t
|
||||
gen_ecc (int algo, unsigned int nbits, KBNODE pub_root,
|
||||
u32 timestamp, u32 expireval, int is_subkey,
|
||||
int keygen_flags, char **cache_nonce_addr)
|
||||
{
|
||||
int rc;
|
||||
PACKET *pkt;
|
||||
PKT_public_key *pk;
|
||||
|
||||
rc = pk_ecc_keypair_gen( &pk, algo, keygen_flags, cache_nonce_addr, nbits );
|
||||
if( rc )
|
||||
return rc;
|
||||
|
||||
/* the rest is very similar to common_gen */
|
||||
|
||||
pk->timestamp = timestamp;
|
||||
if (expireval)
|
||||
pk->expiredate = pk->timestamp + expireval;
|
||||
|
||||
//assert( pk->seckey_info != NULL );
|
||||
/// TODO: the new agent-based model doesn't return private portion here (the pkey array is allocated, but private MPIs are NULL, so this will cause a crash... )
|
||||
///pk->seckey_info->csum = checksum_mpi ( pk->pkey[algo==PUBKEY_ALGO_ECDSA ? 2 : 3] ); /* corresponds to 'd' in 'cqd' or 'cqpd' */
|
||||
|
||||
pkt = xmalloc_clear(sizeof *pkt);
|
||||
pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
|
||||
pkt->pkt.public_key = pk;
|
||||
add_kbnode(pub_root, new_kbnode( pkt ));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Generate an RSA key.
|
||||
@ -1557,6 +1754,8 @@ ask_algo (int addmode, int *r_subkey_algo, unsigned int *r_usage)
|
||||
tty_printf (_(" (%d) RSA (set your own capabilities)\n"), 8 );
|
||||
}
|
||||
|
||||
tty_printf (_(" (%d) ECDSA and ECDH\n"), 9 );
|
||||
|
||||
for(;;)
|
||||
{
|
||||
*r_usage = 0;
|
||||
@ -1613,6 +1812,12 @@ ask_algo (int addmode, int *r_subkey_algo, unsigned int *r_usage)
|
||||
*r_usage = ask_key_flags (algo, addmode);
|
||||
break;
|
||||
}
|
||||
else if (algo == 9)
|
||||
{
|
||||
algo = PUBKEY_ALGO_ECDSA;
|
||||
*r_subkey_algo = PUBKEY_ALGO_ECDH;
|
||||
break;
|
||||
}
|
||||
else
|
||||
tty_printf (_("Invalid selection.\n"));
|
||||
}
|
||||
@ -1657,13 +1862,20 @@ ask_keysize (int algo, unsigned int primary_keysize)
|
||||
max=3072;
|
||||
break;
|
||||
|
||||
case PUBKEY_ALGO_ECDSA:
|
||||
case PUBKEY_ALGO_ECDH:
|
||||
min=256;
|
||||
def=256;
|
||||
max=521;
|
||||
break;
|
||||
|
||||
case PUBKEY_ALGO_RSA:
|
||||
min=1024;
|
||||
break;
|
||||
}
|
||||
|
||||
tty_printf(_("%s keys may be between %u and %u bits long.\n"),
|
||||
gcry_pk_algo_name (algo), min, max);
|
||||
openpgp_pk_algo_name (algo), min, max);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
@ -1682,7 +1894,7 @@ ask_keysize (int algo, unsigned int primary_keysize)
|
||||
|
||||
if(nbits<min || nbits>max)
|
||||
tty_printf(_("%s keysizes must be in the range %u-%u\n"),
|
||||
gcry_pk_algo_name (algo), min, max);
|
||||
openpgp_pk_algo_name (algo), min, max);
|
||||
else
|
||||
break;
|
||||
}
|
||||
@ -1692,10 +1904,18 @@ ask_keysize (int algo, unsigned int primary_keysize)
|
||||
leave:
|
||||
if( algo == PUBKEY_ALGO_DSA && (nbits % 64) )
|
||||
{
|
||||
nbits = ((nbits + 63) / 64) * 64;
|
||||
if (!autocomp)
|
||||
tty_printf(_("rounded up to %u bits\n"), nbits );
|
||||
if( !(algo == PUBKEY_ALGO_ECDSA && nbits==521) ) {
|
||||
nbits = ((nbits + 63) / 64) * 64;
|
||||
if (!autocomp)
|
||||
tty_printf(_("rounded up to %u bits\n"), nbits );
|
||||
}
|
||||
}
|
||||
else if( algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA ) {
|
||||
if( nbits != 256 && nbits != 384 && nbits != 521 ) {
|
||||
nbits = min;
|
||||
tty_printf(_("unsupported ECDH value, corrected to the minimum %u bits\n"), nbits );
|
||||
}
|
||||
}
|
||||
else if( (nbits % 32) )
|
||||
{
|
||||
nbits = ((nbits + 31) / 32) * 32;
|
||||
@ -2185,6 +2405,9 @@ do_create (int algo, unsigned int nbits, KBNODE pub_root,
|
||||
else if (algo == PUBKEY_ALGO_DSA)
|
||||
err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey,
|
||||
keygen_flags, cache_nonce_addr);
|
||||
else if( algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH )
|
||||
err = gen_ecc (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
|
||||
keygen_flags, cache_nonce_addr);
|
||||
else if (algo == PUBKEY_ALGO_RSA)
|
||||
err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
|
||||
keygen_flags, cache_nonce_addr);
|
||||
|
26
g10/keyid.c
26
g10/keyid.c
@ -57,6 +57,8 @@ pubkey_letter( int algo )
|
||||
case PUBKEY_ALGO_ELGAMAL_E: return 'g';
|
||||
case PUBKEY_ALGO_ELGAMAL: return 'G' ;
|
||||
case PUBKEY_ALGO_DSA: return 'D' ;
|
||||
case PUBKEY_ALGO_ECDSA: return 'E' ; // ECC DSA (sign only)
|
||||
case PUBKEY_ALGO_ECDH: return 'e' ; // ECC DH (encrypt only)
|
||||
default: return '?';
|
||||
}
|
||||
}
|
||||
@ -74,6 +76,8 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
|
||||
unsigned int nbits;
|
||||
size_t nbytes;
|
||||
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 */
|
||||
if(pk->version<4)
|
||||
@ -90,11 +94,13 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
|
||||
{
|
||||
for(i=0; i < npkey; i++ )
|
||||
{
|
||||
if (gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, pk->pkey[i]))
|
||||
const 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 (gcry_mpi_print (fmt, NULL, 0, &nbytes, pk->pkey[i]))
|
||||
BUG ();
|
||||
pp[i] = xmalloc (nbytes);
|
||||
if (gcry_mpi_print (GCRYMPI_FMT_PGP, pp[i], nbytes,
|
||||
&nbytes, pk->pkey[i]))
|
||||
if (gcry_mpi_print (fmt, pp[i], nbytes, &nbytes, pk->pkey[i]))
|
||||
BUG ();
|
||||
nn[i] = nbytes;
|
||||
n += nn[i];
|
||||
@ -712,6 +718,20 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
|
||||
pk->pkey[0], pk->pkey[1]);
|
||||
break;
|
||||
|
||||
case PUBKEY_ALGO_ECDSA:
|
||||
case PUBKEY_ALGO_ECDH:
|
||||
err = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(ecc(c%m)(q%m)))",
|
||||
pk->pkey[0], pk->pkey[1]);
|
||||
break;
|
||||
/*
|
||||
case PUBKEY_ALGO_ECDH:
|
||||
err = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(ecdh(c%m)(q%m)(p%m)))",
|
||||
pk->pkey[0], pk->pkey[1], pk->pkey[2]);
|
||||
break;
|
||||
*/
|
||||
|
||||
default:
|
||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
break;
|
||||
|
13
g10/main.h
13
g10/main.h
@ -93,11 +93,12 @@ int map_cipher_openpgp_to_gcry (int algo);
|
||||
int openpgp_cipher_blocklen (int algo);
|
||||
int openpgp_cipher_test_algo( int algo );
|
||||
const char *openpgp_cipher_algo_name (int algo);
|
||||
int map_pk_openpgp_to_gcry (int algo);
|
||||
int openpgp_pk_test_algo( int algo );
|
||||
int openpgp_pk_test_algo2 ( int algo, unsigned int use );
|
||||
int openpgp_pk_algo_usage ( int algo );
|
||||
const char *openpgp_pk_algo_name (int algo);
|
||||
int openpgp_md_test_algo( int algo );
|
||||
const char *openpgp_pk_algo_name (int algo);
|
||||
const char *openpgp_md_algo_name (int algo);
|
||||
|
||||
#ifdef USE_IDEA
|
||||
@ -157,6 +158,10 @@ int pubkey_get_nsig( int algo );
|
||||
int pubkey_get_nenc( int algo );
|
||||
unsigned int pubkey_nbits( int algo, gcry_mpi_t *pkey );
|
||||
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_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 );
|
||||
|
||||
/*-- status.c --*/
|
||||
void set_status_fd ( int fd );
|
||||
@ -251,6 +256,10 @@ gpg_error_t generate_card_subkeypair (kbnode_t pub_keyblock,
|
||||
int save_unprotected_key_to_card (PKT_public_key *sk, int keyno);
|
||||
#endif
|
||||
|
||||
#define KEYGEN_FLAG_NO_PROTECTION 1
|
||||
#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);
|
||||
|
||||
/*-- openfile.c --*/
|
||||
int overwrite_filep( const char *fname );
|
||||
char *make_outfile_name( const char *iname );
|
||||
@ -261,7 +270,7 @@ void try_make_homedir( const char *fname );
|
||||
|
||||
/*-- seskey.c --*/
|
||||
void make_session_key( DEK *dek );
|
||||
gcry_mpi_t encode_session_key( DEK *dek, unsigned nbits );
|
||||
gcry_mpi_t encode_session_key( int openpgp_pk_algo, DEK *dek, unsigned nbits );
|
||||
gcry_mpi_t encode_md_value (PKT_public_key *pk,
|
||||
gcry_md_hd_t md, int hash_algo );
|
||||
|
||||
|
@ -384,6 +384,8 @@ proc_pubkey_enc( CTX c, PACKET *pkt )
|
||||
}
|
||||
else if( is_ELGAMAL(enc->pubkey_algo)
|
||||
|| enc->pubkey_algo == PUBKEY_ALGO_DSA
|
||||
|| enc->pubkey_algo == PUBKEY_ALGO_ECDSA
|
||||
|| enc->pubkey_algo == PUBKEY_ALGO_ECDH
|
||||
|| is_RSA(enc->pubkey_algo)
|
||||
|| enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL) {
|
||||
/* Note that we also allow type 20 Elgamal keys for decryption.
|
||||
@ -450,7 +452,7 @@ print_pkenc_list( struct kidlist_item *list, int failed )
|
||||
if ( !failed && list->reason )
|
||||
continue;
|
||||
|
||||
algstr = gcry_pk_algo_name ( list->pubkey_algo );
|
||||
algstr = openpgp_pk_algo_name ( list->pubkey_algo );
|
||||
pk = xmalloc_clear( sizeof *pk );
|
||||
|
||||
if( !algstr )
|
||||
@ -1616,7 +1618,7 @@ check_sig_and_print( CTX c, KBNODE node )
|
||||
|
||||
/* (Indendation below not yet changed to GNU style.) */
|
||||
|
||||
astr = gcry_pk_algo_name ( sig->pubkey_algo );
|
||||
astr = openpgp_pk_algo_name ( sig->pubkey_algo );
|
||||
if(keystrlen()>8)
|
||||
{
|
||||
log_info(_("Signature made %s\n"),asctimestamp(sig->timestamp));
|
||||
|
147
g10/misc.c
147
g10/misc.c
@ -64,6 +64,7 @@
|
||||
#include "call-agent.h"
|
||||
#include "i18n.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static int
|
||||
string_count_chr (const char *string, int c)
|
||||
@ -294,7 +295,7 @@ print_pubkey_algo_note( int algo )
|
||||
{
|
||||
warn=1;
|
||||
log_info (_("WARNING: using experimental public key algorithm %s\n"),
|
||||
gcry_pk_algo_name (algo));
|
||||
openpgp_cipher_algo_name (algo));
|
||||
}
|
||||
}
|
||||
else if (algo == 20)
|
||||
@ -365,6 +366,12 @@ map_cipher_gcry_to_openpgp (int algo)
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
map_pk_openpgp_to_gcry (int algo)
|
||||
{
|
||||
return (algo==PUBKEY_ALGO_ECDSA ? GCRY_PK_ECDSA : (algo==PUBKEY_ALGO_ECDH ? GCRY_PK_ECDH : algo));
|
||||
}
|
||||
|
||||
|
||||
/* Return the block length of an OpenPGP cipher algorithm. */
|
||||
int
|
||||
@ -409,7 +416,13 @@ openpgp_cipher_test_algo( int algo )
|
||||
const char *
|
||||
openpgp_cipher_algo_name (int algo)
|
||||
{
|
||||
return gnupg_cipher_algo_name (map_cipher_openpgp_to_gcry (algo));
|
||||
return gcry_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
|
||||
@ -424,7 +437,13 @@ openpgp_pk_test_algo( int algo )
|
||||
|
||||
if (algo < 0 || algo > 110)
|
||||
return gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
return gcry_pk_test_algo (algo);
|
||||
|
||||
if( algo == PUBKEY_ALGO_ECDSA )
|
||||
algo = GCRY_PK_ECDSA;
|
||||
else if( algo == PUBKEY_ALGO_ECDH )
|
||||
algo = GCRY_PK_ECDH;
|
||||
|
||||
return gcry_pk_test_algo ( algo );
|
||||
}
|
||||
|
||||
int
|
||||
@ -442,7 +461,12 @@ openpgp_pk_test_algo2( int algo, unsigned int use )
|
||||
if (algo < 0 || algo > 110)
|
||||
return gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
|
||||
return gcry_pk_algo_info (algo, GCRYCTL_TEST_ALGO, NULL, &use_buf);
|
||||
if( algo == PUBKEY_ALGO_ECDSA )
|
||||
algo = GCRY_PK_ECDSA;
|
||||
else if( algo == PUBKEY_ALGO_ECDH )
|
||||
algo = GCRY_PK_ECDH;
|
||||
|
||||
return gcry_pk_algo_info ( algo, GCRYCTL_TEST_ALGO, NULL, &use_buf);
|
||||
}
|
||||
|
||||
int
|
||||
@ -457,6 +481,7 @@ openpgp_pk_algo_usage ( int algo )
|
||||
| PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH);
|
||||
break;
|
||||
case PUBKEY_ALGO_RSA_E:
|
||||
case PUBKEY_ALGO_ECDH:
|
||||
use = PUBKEY_USAGE_ENC;
|
||||
break;
|
||||
case PUBKEY_ALGO_RSA_S:
|
||||
@ -472,6 +497,8 @@ openpgp_pk_algo_usage ( int algo )
|
||||
case PUBKEY_ALGO_DSA:
|
||||
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
|
||||
break;
|
||||
case PUBKEY_ALGO_ECDSA:
|
||||
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -480,7 +507,7 @@ openpgp_pk_algo_usage ( int algo )
|
||||
|
||||
/* Map the OpenPGP pubkey algorithm whose ID is contained in ALGO to a
|
||||
string representation of the algorithm name. For unknown algorithm
|
||||
IDs this function returns "?". */
|
||||
IDs this function returns "?".
|
||||
const char *
|
||||
openpgp_pk_algo_name (int algo)
|
||||
{
|
||||
@ -498,6 +525,7 @@ openpgp_pk_algo_name (int algo)
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
int
|
||||
@ -1348,6 +1376,10 @@ pubkey_get_npkey( int algo )
|
||||
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
else if (algo == PUBKEY_ALGO_ECDSA)
|
||||
algo = GCRY_PK_ECDSA;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
algo = GCRY_PK_ECDH;
|
||||
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &n))
|
||||
n = 0;
|
||||
return n;
|
||||
@ -1361,6 +1393,10 @@ pubkey_get_nskey( int algo )
|
||||
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
else if (algo == PUBKEY_ALGO_ECDSA)
|
||||
algo = GCRY_PK_ECDSA;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
algo = GCRY_PK_ECDH;
|
||||
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &n ))
|
||||
n = 0;
|
||||
return n;
|
||||
@ -1374,6 +1410,10 @@ pubkey_get_nsig( int algo )
|
||||
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
else if (algo == PUBKEY_ALGO_ECDSA)
|
||||
algo = GCRY_PK_ECDSA;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
algo = GCRY_PK_ECDH;
|
||||
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSIGN, NULL, &n))
|
||||
n = 0;
|
||||
return n;
|
||||
@ -1387,6 +1427,10 @@ pubkey_get_nenc( int algo )
|
||||
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
else if (algo == PUBKEY_ALGO_ECDSA)
|
||||
algo = GCRY_PK_ECDSA;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
algo = GCRY_PK_ECDH;
|
||||
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NENCR, NULL, &n ))
|
||||
n = 0;
|
||||
return n;
|
||||
@ -1400,6 +1444,8 @@ pubkey_nbits( int algo, gcry_mpi_t *key )
|
||||
int rc, nbits;
|
||||
gcry_sexp_t sexp;
|
||||
|
||||
assert( algo != GCRY_PK_ECDSA && algo != GCRY_PK_ECDH );
|
||||
|
||||
if( algo == GCRY_PK_DSA ) {
|
||||
rc = gcry_sexp_build ( &sexp, NULL,
|
||||
"(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
|
||||
@ -1415,6 +1461,11 @@ pubkey_nbits( int algo, gcry_mpi_t *key )
|
||||
"(public-key(rsa(n%m)(e%m)))",
|
||||
key[0], key[1] );
|
||||
}
|
||||
else if( algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH ) {
|
||||
rc = gcry_sexp_build ( &sexp, NULL,
|
||||
"(public-key(ecc(c%m)(q%m)))",
|
||||
key[0], key[1] /* not affecting the size calculation, so use 'ecc' == 'ecdsa' */ );
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
@ -1455,3 +1506,89 @@ mpi_print (estream_t fp, gcry_mpi_t a, int mode)
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a special size+body mpi a, to OUT. The format of the content of the MPI is
|
||||
* one byte LEN, following by LEN bytes
|
||||
*/
|
||||
int
|
||||
iobuf_write_size_body_mpi (iobuf_t out, gcry_mpi_t a)
|
||||
{
|
||||
byte buffer[256]; /* Fixed buffer for a public parameter, max possible */
|
||||
size_t nbytes = (mpi_get_nbits (a)+7)/8;
|
||||
int rc;
|
||||
|
||||
if( nbytes > sizeof(buffer) ) {
|
||||
log_error("mpi with size+body is too large (%u bytes)\n", nbytes);
|
||||
return gpg_error (GPG_ERR_TOO_LARGE);
|
||||
}
|
||||
|
||||
rc = gcry_mpi_print (GCRYMPI_FMT_USG, buffer, sizeof(buffer), &nbytes, a);
|
||||
if( rc ) {
|
||||
log_error("Failed to exported size+body mpi\n");
|
||||
return rc;
|
||||
}
|
||||
if( nbytes < 2 || buffer[0] != nbytes-1 ) {
|
||||
if( nbytes > 2 )
|
||||
log_error("Internal size mismatch in mpi size+body: %02x != %02x (other bytes: %02x %02x ... %02x %02x)\n",
|
||||
buffer[0], nbytes-1, buffer[1], buffer[2], buffer[nbytes-2], buffer[nbytes-1]);
|
||||
else
|
||||
log_error("Internal size mismatch in mpi size+body: only %d bytes\n", nbytes );
|
||||
return gpg_error (GPG_ERR_INV_DATA);
|
||||
}
|
||||
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.
|
||||
* On success the number of consumed bytes will body[0]+1.
|
||||
* The format of the content of the 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).
|
||||
*/
|
||||
int
|
||||
iobuf_read_size_body( iobuf_t inp, byte *body, int body_max_size, int pktlen, gcry_mpi_t *out ) {
|
||||
unsigned n;
|
||||
int rc;
|
||||
gcry_mpi_t result;
|
||||
|
||||
*out = NULL;
|
||||
|
||||
if( (n = iobuf_readbyte(inp)) == -1 ) {
|
||||
return G10ERR_INVALID_PACKET;
|
||||
}
|
||||
if( n >= body_max_size || n < 2) {
|
||||
log_error("invalid size+body field\n");
|
||||
return G10ERR_INVALID_PACKET;
|
||||
}
|
||||
body[0] = n;
|
||||
if( (n = iobuf_read(inp, body+1, n)) == -1 ) {
|
||||
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");
|
||||
return G10ERR_INVALID_PACKET;
|
||||
}
|
||||
rc = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, body, n+1, NULL);
|
||||
if (rc)
|
||||
log_fatal ("mpi_scan failed: %s\n", gpg_strerror (rc));
|
||||
|
||||
*out = result;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* pkey[1] or skey[1] is Q for ECDSA, which is an uncompressed point, i.e. 04 <x> <y> */
|
||||
int ecdsa_qbits_from_Q( int qbits ) {
|
||||
if( qbits%8>3 ) {
|
||||
log_error(_("ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"));
|
||||
return 0;
|
||||
}
|
||||
qbits -= qbits%8;
|
||||
qbits /= 2;
|
||||
return qbits;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -939,20 +939,40 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
}
|
||||
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);
|
||||
}
|
||||
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];
|
||||
assert( ndata == 2 );
|
||||
n = pktlen; k->data[0] = mpi_read(inp, &n, 0); pktlen -=n;
|
||||
rc = iobuf_read_size_body( inp, encr_buf, sizeof(encr_buf), pktlen, k->data+1 );
|
||||
if( rc )
|
||||
goto leave;
|
||||
if( list_mode ) {
|
||||
es_fprintf (listfp, "\tdata: ");
|
||||
mpi_print(listfp, k->data[0], mpi_print_mode );
|
||||
es_putc ('\n', listfp);
|
||||
es_fprintf (listfp, "\tdata: [% 3d bytes] ", encr_buf[0]);
|
||||
mpi_print(listfp, k->data[1], mpi_print_mode );
|
||||
es_putc ('\n', listfp);
|
||||
}
|
||||
pktlen -= (encr_buf[0]+1);
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
@ -1926,20 +1946,61 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
else
|
||||
{
|
||||
/* Fill in public key parameters. */
|
||||
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( algorithm != PUBKEY_ALGO_ECDSA && algorithm != PUBKEY_ALGO_ECDH ) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* note that the code in this function ignores the errors */
|
||||
byte name_oid[256];
|
||||
err = iobuf_read_size_body( inp, name_oid, sizeof(name_oid), pktlen, pk->pkey+0 );
|
||||
if( err )
|
||||
goto leave;
|
||||
n = name_oid[0];
|
||||
if( list_mode )
|
||||
es_fprintf (listfp, "\tpkey[0]: curve OID [%d] ...%02x %02x\n",
|
||||
n, name_oid[1+n-2], name_oid[1+n-1] );
|
||||
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);
|
||||
}
|
||||
if (!pk->pkey[i])
|
||||
err = gpg_error (GPG_ERR_INV_PACKET);
|
||||
}
|
||||
/* One more field for 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 );
|
||||
if( err )
|
||||
goto leave;
|
||||
n = kek_params[0];
|
||||
if( kek_params[1] != 1 ) {
|
||||
log_error("invalid ecdh KEK parameters field type in private key: understand type 1, but found 0x%02x\n", kek_params[1]);
|
||||
err = gpg_error(G10ERR_INVALID_PACKET);
|
||||
goto leave;
|
||||
}
|
||||
if( list_mode )
|
||||
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] );
|
||||
pktlen -= (n+1);
|
||||
#undef kek_params
|
||||
}
|
||||
}
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat,
|
||||
{
|
||||
char *uid;
|
||||
size_t uidlen;
|
||||
const char *algo_name = gcry_pk_algo_name ( pk->pubkey_algo );
|
||||
const char *algo_name = openpgp_pk_algo_name ( pk->pubkey_algo );
|
||||
const char *timestr;
|
||||
char *maink;
|
||||
|
||||
@ -585,7 +585,7 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo,
|
||||
|
||||
if ( !get_pubkey( pk, keyid ) )
|
||||
{
|
||||
const char *s = gcry_pk_algo_name ( pk->pubkey_algo );
|
||||
const char *s = openpgp_pk_algo_name ( pk->pubkey_algo );
|
||||
|
||||
tty_printf (_("%u-bit %s key, ID %s, created %s"),
|
||||
nbits_from_pk( pk ), s?s:"?", keystr(keyid),
|
||||
@ -690,7 +690,7 @@ gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped)
|
||||
char *desc;
|
||||
const char *prompt;
|
||||
|
||||
algo_name = gcry_pk_algo_name (pk->pubkey_algo);
|
||||
algo_name = openpgp_pk_algo_name (pk->pubkey_algo);
|
||||
timestr = strtimestamp (pk->timestamp);
|
||||
uid = get_user_id (pk->keyid, &uidlen);
|
||||
|
||||
|
151
g10/pkglue.c
151
g10/pkglue.c
@ -27,9 +27,10 @@
|
||||
#include "gpg.h"
|
||||
#include "util.h"
|
||||
#include "pkglue.h"
|
||||
#include "main.h"
|
||||
|
||||
|
||||
static gcry_mpi_t
|
||||
gcry_mpi_t
|
||||
mpi_from_sexp (gcry_sexp_t sexp, const char * item)
|
||||
{
|
||||
gcry_sexp_t list;
|
||||
@ -44,6 +45,70 @@ 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
|
||||
@ -54,25 +119,31 @@ 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;
|
||||
int rc;
|
||||
const int gcry_pkalgo = map_pk_openpgp_to_gcry( algo );
|
||||
|
||||
/* make a sexp from pkey */
|
||||
if (algo == GCRY_PK_DSA)
|
||||
if (gcry_pkalgo == GCRY_PK_DSA)
|
||||
{
|
||||
rc = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
|
||||
pkey[0], pkey[1], pkey[2], pkey[3]);
|
||||
}
|
||||
else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
|
||||
else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
|
||||
{
|
||||
rc = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(elg(p%m)(g%m)(y%m)))",
|
||||
pkey[0], pkey[1], pkey[2]);
|
||||
}
|
||||
else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_S)
|
||||
else if (gcry_pkalgo == GCRY_PK_RSA || gcry_pkalgo == GCRY_PK_RSA_S)
|
||||
{
|
||||
rc = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
|
||||
}
|
||||
else if (gcry_pkalgo == GCRY_PK_ECDSA) /* same as GCRY_PK_ECDH */
|
||||
{
|
||||
rc = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(ecdsa(c%m)(q%m)))", pkey[0], pkey[1]);
|
||||
}
|
||||
else
|
||||
return GPG_ERR_PUBKEY_ALGO;
|
||||
|
||||
@ -85,7 +156,7 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
|
||||
|
||||
/* Put data into a S-Exp s_sig. */
|
||||
s_sig = NULL;
|
||||
if (algo == GCRY_PK_DSA)
|
||||
if (gcry_pkalgo == GCRY_PK_DSA)
|
||||
{
|
||||
if (!data[0] || !data[1])
|
||||
rc = gpg_error (GPG_ERR_BAD_MPI);
|
||||
@ -93,7 +164,15 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
|
||||
rc = gcry_sexp_build (&s_sig, NULL,
|
||||
"(sig-val(dsa(r%m)(s%m)))", data[0], data[1]);
|
||||
}
|
||||
else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
|
||||
else if (gcry_pkalgo == GCRY_PK_ECDSA)
|
||||
{
|
||||
if (!data[0] || !data[1])
|
||||
rc = gpg_error (GPG_ERR_BAD_MPI);
|
||||
else
|
||||
rc = gcry_sexp_build (&s_sig, NULL,
|
||||
"(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]);
|
||||
}
|
||||
else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
|
||||
{
|
||||
if (!data[0] || !data[1])
|
||||
rc = gpg_error (GPG_ERR_BAD_MPI);
|
||||
@ -101,7 +180,7 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
|
||||
rc = gcry_sexp_build (&s_sig, NULL,
|
||||
"(sig-val(elg(r%m)(s%m)))", data[0], data[1]);
|
||||
}
|
||||
else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_S)
|
||||
else if (gcry_pkalgo == GCRY_PK_RSA || gcry_pkalgo == GCRY_PK_RSA_S)
|
||||
{
|
||||
if (!data[0])
|
||||
rc = gpg_error (GPG_ERR_BAD_MPI);
|
||||
@ -128,7 +207,7 @@ 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.
|
||||
*/
|
||||
int
|
||||
pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, 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;
|
||||
int rc;
|
||||
@ -146,6 +225,10 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, gcry_mpi_t * pkey)
|
||||
"(public-key(rsa(n%m)(e%m)))",
|
||||
pkey[0], pkey[1]);
|
||||
}
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
return pk_ecdh_encrypt( resarr, pk_fp, data, pkey );
|
||||
}
|
||||
else
|
||||
return GPG_ERR_PUBKEY_ALGO;
|
||||
|
||||
@ -166,7 +249,7 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, gcry_mpi_t * pkey)
|
||||
else
|
||||
{ /* add better error handling or make gnupg use S-Exp directly */
|
||||
resarr[0] = mpi_from_sexp (s_ciph, "a");
|
||||
if (algo != GCRY_PK_RSA && algo != GCRY_PK_RSA_E)
|
||||
if (algo != GCRY_PK_RSA && algo != GCRY_PK_RSA_E && algo != PUBKEY_ALGO_ECDH)
|
||||
resarr[1] = mpi_from_sexp (s_ciph, "b");
|
||||
}
|
||||
|
||||
@ -181,7 +264,7 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, gcry_mpi_t * pkey)
|
||||
* change the internal design to directly fit to libgcrypt.
|
||||
*/
|
||||
int
|
||||
pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data,
|
||||
pk_decrypt (int algo, gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t * data,
|
||||
gcry_mpi_t * skey)
|
||||
{
|
||||
gcry_sexp_t s_skey, s_data, s_plain;
|
||||
@ -202,6 +285,9 @@ pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data,
|
||||
skey[0], skey[1], skey[2], skey[3], skey[4],
|
||||
skey[5]);
|
||||
}
|
||||
else if( algo == PUBKEY_ALGO_ECDH ) {
|
||||
return pk_ecdh_decrypt( result, sk_fp, data, skey );
|
||||
}
|
||||
else
|
||||
return GPG_ERR_PUBKEY_ALGO;
|
||||
|
||||
@ -244,3 +330,48 @@ pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Check whether SKEY is a suitable secret key. */
|
||||
int
|
||||
pk_check_secret_key (int algo, gcry_mpi_t *skey)
|
||||
{
|
||||
gcry_sexp_t s_skey;
|
||||
int rc;
|
||||
const int gcry_pkalgo = map_pk_openpgp_to_gcry( algo );
|
||||
|
||||
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_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_RSA
|
||||
|| gcry_pkalgo == GCRY_PK_RSA_S || gcry_pkalgo == GCRY_PK_RSA_E)
|
||||
{
|
||||
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_ECDSA || gcry_pkalgo == GCRY_PK_ECDH)
|
||||
{
|
||||
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)
|
||||
{
|
||||
rc = gcry_pk_testkey (s_skey);
|
||||
gcry_sexp_release (s_skey);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
12
g10/pkglue.h
12
g10/pkglue.h
@ -20,13 +20,23 @@
|
||||
#ifndef GNUPG_G10_PKGLUE_H
|
||||
#define GNUPG_G10_PKGLUE_H
|
||||
|
||||
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,
|
||||
gcry_mpi_t *pkey);
|
||||
int pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
|
||||
const byte fp[MAX_FINGERPRINT_LEN],
|
||||
gcry_mpi_t *pkey);
|
||||
int pk_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
|
||||
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_ecdh_encrypt (gcry_mpi_t * resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], 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 * skey);
|
||||
|
||||
gcry_mpi_t pk_ecdh_default_params_to_mpi( int qbits );
|
||||
byte *pk_ecdh_default_params( int qbits, size_t *sizeout );
|
||||
|
||||
#endif /*GNUPG_G10_PKGLUE_H*/
|
||||
|
@ -145,6 +145,8 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
|
||||
gcry_sexp_t s_data;
|
||||
char *desc;
|
||||
char *keygrip;
|
||||
byte fp[MAX_FINGERPRINT_LEN];
|
||||
size_t fpn;
|
||||
|
||||
/* Get the keygrip. */
|
||||
err = hexkeygrip_from_pk (sk, &keygrip);
|
||||
@ -174,9 +176,12 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
fingerprint_from_pk( sk, fp, &fpn );
|
||||
assert( fpn == 20 );
|
||||
|
||||
/* Decrypt. */
|
||||
desc = gpg_format_keydesc (sk, 0, 1);
|
||||
err = agent_pkdecrypt (NULL, keygrip, desc, s_data, &frame, &nframe);
|
||||
err = agent_pkdecrypt (NULL, keygrip, desc, s_data, fp, &frame, &nframe);
|
||||
xfree (desc);
|
||||
gcry_sexp_release (s_data);
|
||||
if (err)
|
||||
@ -202,28 +207,41 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("DEK frame:", frame, nframe);
|
||||
n = 0;
|
||||
if (!card)
|
||||
{
|
||||
if (n + 7 > nframe)
|
||||
{
|
||||
err = gpg_error (G10ERR_WRONG_SECKEY);
|
||||
goto leave;
|
||||
}
|
||||
if (frame[n] == 1 && frame[nframe - 1] == 2)
|
||||
{
|
||||
log_info (_("old encoding of the DEK is not supported\n"));
|
||||
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. */
|
||||
|
||||
if( sk->pubkey_algo != PUBKEY_ALGO_ECDH ) {
|
||||
if (!card)
|
||||
{
|
||||
if (n + 7 > nframe)
|
||||
{
|
||||
err = gpg_error (G10ERR_WRONG_SECKEY);
|
||||
goto leave;
|
||||
}
|
||||
if (frame[n] == 1 && frame[nframe - 1] == 2)
|
||||
{
|
||||
log_info (_("old encoding of the DEK is not supported\n"));
|
||||
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 {
|
||||
/* Allow double padding for the benefit of DEK size concealment.
|
||||
* Higher than this is wasteful.
|
||||
*/
|
||||
if( frame[nframe-1] > 8*2 || nframe <= 8 ) {
|
||||
err = G10ERR_WRONG_SECKEY; goto leave;
|
||||
}
|
||||
nframe -= frame[nframe-1]; /* remove padding */
|
||||
assert( n==0 ); /* used just bellow */
|
||||
}
|
||||
|
||||
if (n + 4 > nframe)
|
||||
{
|
||||
|
69
g10/seskey.c
69
g10/seskey.c
@ -27,6 +27,7 @@
|
||||
#include "gpg.h"
|
||||
#include "util.h"
|
||||
#include "cipher.h"
|
||||
#include "options.h"
|
||||
#include "main.h"
|
||||
#include "i18n.h"
|
||||
|
||||
@ -73,15 +74,48 @@ make_session_key( DEK *dek )
|
||||
* returns: A mpi with the session key (caller must free)
|
||||
*/
|
||||
gcry_mpi_t
|
||||
encode_session_key (DEK *dek, unsigned int nbits)
|
||||
encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
|
||||
{
|
||||
size_t nframe = (nbits+7) / 8;
|
||||
byte *p;
|
||||
byte *frame;
|
||||
int i,n;
|
||||
u16 csum;
|
||||
u16 csum = 0;
|
||||
gcry_mpi_t a;
|
||||
|
||||
if( DBG_CIPHER )
|
||||
log_debug("encode_session_key: encoding %d byte DEK", dek->keylen);
|
||||
|
||||
for( p = dek->key, i=0; i < dek->keylen; i++ )
|
||||
csum += *p++;
|
||||
|
||||
/* Shortcut for ECDH. It's padding is minimal to simply make the 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);
|
||||
assert( !(nframe%8) && nframe > 1 + dek->keylen + 2 ); /* alg+key+csum fit and the size is congruent to 8 */
|
||||
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 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.
|
||||
@ -103,9 +137,6 @@ encode_session_key (DEK *dek, unsigned int nbits)
|
||||
* cipher algorithm (20 is used with blowfish160).
|
||||
* CSUM is the 16 bit checksum over the DEK
|
||||
*/
|
||||
csum = 0;
|
||||
for( p = dek->key, i=0; i < dek->keylen; i++ )
|
||||
csum += *p++;
|
||||
|
||||
frame = xmalloc_secure( nframe );
|
||||
n = 0;
|
||||
@ -161,8 +192,8 @@ do_encode_md( gcry_md_hd_t md, int algo, size_t len, unsigned nbits,
|
||||
gcry_mpi_t a;
|
||||
|
||||
if( len + asnlen + 4 > nframe )
|
||||
log_bug("can't encode a %d bit MD into a %d bits frame\n",
|
||||
(int)(len*8), (int)nbits);
|
||||
log_bug("can't encode a %d bit MD into a %d bits frame, algo=%d\n",
|
||||
(int)(len*8), (int)nbits, algo);
|
||||
|
||||
/* We encode the MD in this way:
|
||||
*
|
||||
@ -209,16 +240,23 @@ gcry_mpi_t
|
||||
encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
|
||||
{
|
||||
gcry_mpi_t frame;
|
||||
int gcry_pkalgo;
|
||||
|
||||
assert (hash_algo);
|
||||
assert (pk);
|
||||
|
||||
if (pk->pubkey_algo == GCRY_PK_DSA)
|
||||
gcry_pkalgo = map_pk_openpgp_to_gcry( pk->pubkey_algo );
|
||||
|
||||
if (gcry_pkalgo == GCRY_PK_DSA || gcry_pkalgo == GCRY_PK_ECDSA )
|
||||
{
|
||||
/* It's a DSA signature, so find out the size of q. */
|
||||
|
||||
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> */
|
||||
if( gcry_pkalgo==GCRY_PK_ECDSA )
|
||||
qbytes = ecdsa_qbits_from_Q( qbytes );
|
||||
|
||||
/* Make sure it is a multiple of 8 bits. */
|
||||
|
||||
if(qbytes%8)
|
||||
@ -236,7 +274,8 @@ encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
|
||||
DSA. ;) */
|
||||
if (qbytes < 160)
|
||||
{
|
||||
log_error (_("DSA 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 ),
|
||||
keystr_from_pk (pk), qbytes);
|
||||
return NULL;
|
||||
}
|
||||
@ -245,10 +284,16 @@ encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
|
||||
|
||||
/* Check if we're too short. Too long is safe as we'll
|
||||
automatically left-truncate. */
|
||||
if (gcry_md_get_algo_dlen (hash_algo) < qbytes)
|
||||
/* 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.
|
||||
* ( 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) < qbytes )
|
||||
if (gcry_md_get_algo_dlen (hash_algo) < ((gcry_pkalgo==GCRY_PK_ECDSA && qbytes>(521)/8) ? 512/8 : qbytes) )
|
||||
{
|
||||
log_error (_("DSA key %s requires a %zu bit or larger hash\n"),
|
||||
keystr_from_pk(pk), qbytes*8);
|
||||
log_error (_("%s key %s requires a %zu bit or larger hash, used hash-algo=%d\n"),
|
||||
gcry_pk_algo_name( gcry_pkalgo ),
|
||||
keystr_from_pk(pk), qbytes*8, hash_algo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
38
g10/sign.c
38
g10/sign.c
@ -227,21 +227,6 @@ hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static gcry_mpi_t
|
||||
mpi_from_sexp (gcry_sexp_t sexp, const char * item)
|
||||
{
|
||||
gcry_sexp_t list;
|
||||
gcry_mpi_t data;
|
||||
|
||||
list = gcry_sexp_find_token (sexp, item, 0);
|
||||
assert (list);
|
||||
data = gcry_sexp_nth_mpi (list, 1, 0);
|
||||
assert (data);
|
||||
gcry_sexp_release (list);
|
||||
return data;
|
||||
}
|
||||
|
||||
/* Perform the sign operation. If CACHE_NONCE is given the agent is
|
||||
advised to use that cached passphrase fro the key. */
|
||||
static int
|
||||
@ -418,7 +403,7 @@ match_dsa_hash (unsigned int qbytes)
|
||||
if (qbytes <= 48)
|
||||
return DIGEST_ALGO_SHA384;
|
||||
|
||||
if (qbytes <= 64)
|
||||
if (qbytes <= 66 ) /* 66 corresponds to 521 (64 to 512) */
|
||||
return DIGEST_ALGO_SHA512;
|
||||
|
||||
return DEFAULT_DIGEST_ALGO;
|
||||
@ -451,9 +436,13 @@ hash_for (PKT_public_key *pk)
|
||||
{
|
||||
return recipient_digest_algo;
|
||||
}
|
||||
else if (pk->pubkey_algo == PUBKEY_ALGO_DSA)
|
||||
else if(pk->pubkey_algo==PUBKEY_ALGO_DSA || pk->pubkey_algo==PUBKEY_ALGO_ECDSA )
|
||||
{
|
||||
unsigned int qbytes = gcry_mpi_get_nbits (pk->pkey[1]) / 8;
|
||||
unsigned int qbytes = gcry_mpi_get_nbits (pk->pkey[1]);
|
||||
|
||||
if( pk->pubkey_algo==PUBKEY_ALGO_ECDSA )
|
||||
qbytes = ecdsa_qbits_from_Q(qbytes);
|
||||
qbytes = qbytes/8;
|
||||
|
||||
/* 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
|
||||
@ -935,10 +924,13 @@ 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 )
|
||||
{
|
||||
if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA)
|
||||
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])+7/8;
|
||||
int temp_hashlen = gcry_mpi_get_nbits(sk_rover->pk->pkey[1]);
|
||||
|
||||
if( sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA )
|
||||
temp_hashlen = ecdsa_qbits_from_Q( temp_hashlen );
|
||||
temp_hashlen = (temp_hashlen+7)/8;
|
||||
|
||||
/* Pick a hash that is large enough for our
|
||||
largest q */
|
||||
@ -1494,7 +1486,9 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
|
||||
&& pk->version<4 && sigversion<4)
|
||||
digest_algo = DIGEST_ALGO_MD5;
|
||||
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 )
|
||||
digest_algo = match_dsa_hash (ecdsa_qbits_from_Q( gcry_mpi_get_nbits (pksk->pkey[1]) ) / 8);
|
||||
else
|
||||
digest_algo = DIGEST_ALGO_SHA1;
|
||||
}
|
||||
|
30
g10/verify-stubs.c
Normal file
30
g10/verify-stubs.c
Normal file
@ -0,0 +1,30 @@
|
||||
/* To satisfy the linker for the gpgv target
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006,
|
||||
* 2007 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include "gpg.h"
|
||||
#include "main.h"
|
||||
|
||||
int
|
||||
pk_ecc_keypair_gen( PKT_public_key **pk_out, int algo, int keygen_flags, char **cache_nonce_addr, unsigned nbits) {
|
||||
return GPG_ERR_NOT_IMPLEMENTED;
|
||||
}
|
@ -176,5 +176,7 @@ next_tuple (tupledesc_t tupledesc, unsigned int *r_tag, size_t *r_length)
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -38,7 +38,7 @@ const void *find_tuple (tupledesc_t tupledesc,
|
||||
unsigned int tag, size_t *r_length);
|
||||
const void *next_tuple (tupledesc_t tupledesc,
|
||||
unsigned int *r_tag, size_t *r_length);
|
||||
|
||||
char *mpi2hex( gcry_mpi_t m );
|
||||
|
||||
|
||||
#endif /*G13_UTILS_H*/
|
||||
|
@ -56,6 +56,8 @@
|
||||
#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_DSA /* 17 */ GCRY_PK_DSA
|
||||
#define PUBKEY_ALGO_ECDH 18 /* corresponds to GCRY_PK_ECDH ECC DH; encrypt only */
|
||||
#define PUBKEY_ALGO_ECDSA 19 /* corresponds to GCRY_PK_ECDSA ECC DSA; sign only */
|
||||
#define PUBKEY_ALGO_ELGAMAL /* 20 */ GCRY_PK_ELG /* Elgamal encr+sign */
|
||||
|
||||
#define PUBKEY_USAGE_SIG GCRY_PK_USAGE_SIGN /* Good for signatures. */
|
||||
|
@ -186,7 +186,7 @@ next_packet (unsigned char const **bufptr, size_t *buflen,
|
||||
}
|
||||
|
||||
|
||||
/* Parse a key packet and store the ionformation in KI. */
|
||||
/* Parse a key packet and store the information in KI. */
|
||||
static gpg_error_t
|
||||
parse_key (const unsigned char *data, size_t datalen,
|
||||
struct _keybox_openpgp_key_info *ki)
|
||||
@ -243,6 +243,11 @@ parse_key (const unsigned char *data, size_t datalen,
|
||||
case 17: /* DSA */
|
||||
npkey = 4;
|
||||
break;
|
||||
case 18: /* ECDH */
|
||||
npkey = 3;
|
||||
case 19: /* ECDSA */
|
||||
npkey = 2;
|
||||
break;
|
||||
default: /* Unknown algorithm. */
|
||||
return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user