mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Merge branch 'ECC-INTEGRATION-2-1'
This commit is contained in:
commit
38904b697c
132
.gitignore
vendored
132
.gitignore
vendored
@ -4,9 +4,141 @@ autom4te.cache/
|
||||
configure
|
||||
config.h.in
|
||||
config.h
|
||||
config.log
|
||||
config.status
|
||||
common/audit-events.h
|
||||
common/status-codes.h
|
||||
doc/gnupg.info*
|
||||
doc/stamp-vti
|
||||
doc/version.texi
|
||||
po/gnupg2.pot
|
||||
po/POTFILES
|
||||
stamp-h1
|
||||
Makefile
|
||||
.deps/
|
||||
keyserver/gpg2keys_mailto
|
||||
keyserver/gpg2keys_test
|
||||
tools/gpg-zip
|
||||
|
||||
# Files created by make when not using a VPATH build
|
||||
*.o
|
||||
po/en@boldquot.insert-header
|
||||
po/en@boldquot.po
|
||||
po/en@quot.insert-header
|
||||
po/en@quot.po
|
||||
po/stamp-po
|
||||
agent/gpg-agent
|
||||
agent/gpg-preset-passphrase
|
||||
agent/gpg-protect-tool
|
||||
agent/t-protect
|
||||
common/libcommon.a
|
||||
common/libcommonpth.a
|
||||
common/libgpgrl.a
|
||||
common/libsimple-pwquery.a
|
||||
common/t-b64
|
||||
common/t-convert
|
||||
common/t-exechelp
|
||||
common/t-gettime
|
||||
common/t-helpfile
|
||||
common/t-percent
|
||||
common/t-session-env
|
||||
common/t-sexputil
|
||||
common/t-sysutils
|
||||
common/t-stringhelp
|
||||
common/t-timestuff
|
||||
doc/addgnupghome.8
|
||||
doc/applygnupgdefaults.8
|
||||
doc/faq.html
|
||||
doc/faq.raw.xref
|
||||
doc/gnupg-card-architecture.eps
|
||||
doc/gnupg-card-architecture.pdf
|
||||
doc/gnupg-card-architecture.png
|
||||
doc/gnupg.7
|
||||
doc/gpg-agent.1
|
||||
doc/gpg-connect-agent.1
|
||||
doc/gpg-preset-passphrase.1
|
||||
doc/gpg-zip.1
|
||||
doc/gpg2.1
|
||||
doc/gpgconf.1
|
||||
doc/gpgparsemail.1
|
||||
doc/gpgsm-gencert.sh.1
|
||||
doc/gpgsm.1
|
||||
doc/gpgv2.1
|
||||
doc/scdaemon.1
|
||||
doc/dirmngr-client.1
|
||||
doc/dirmngr.8
|
||||
doc/symcryptrun.1
|
||||
doc/watchgnupg.1
|
||||
doc/yat2m
|
||||
doc/yat2m-stamp
|
||||
g10/gpg2
|
||||
g10/gpgv2
|
||||
g10/t-rmd160
|
||||
gl/alloca.h
|
||||
gl/libgnu.a
|
||||
jnlib/libjnlib.a
|
||||
jnlib/t-stringhelp
|
||||
kbx/kbxutil
|
||||
kbx/libkeybox.a
|
||||
keyserver/gpg2keys_curl
|
||||
keyserver/gpg2keys_finger
|
||||
keyserver/gpg2keys_hkp
|
||||
keyserver/gpg2keys_kdns
|
||||
keyserver/gpg2keys_ldap
|
||||
scd/gnupg-pcsc-wrapper
|
||||
scd/scdaemon
|
||||
sm/gpgsm
|
||||
dirmngr/dirmngr
|
||||
dirmngr/dirmngr-client
|
||||
dirmngr/dirmngr_ldap
|
||||
dirmngr/no-libgcrypt.c
|
||||
tests/asschk
|
||||
tests/gpg-agent.conf
|
||||
tests/gpgsm.conf
|
||||
tests/inittests.stamp
|
||||
tests/openpgp/data-32000
|
||||
tests/openpgp/data-500
|
||||
tests/openpgp/data-80000
|
||||
tests/openpgp/data-9000
|
||||
tests/openpgp/gpg-agent.conf
|
||||
tests/openpgp/gpg_dearmor
|
||||
tests/openpgp/plain-1
|
||||
tests/openpgp/plain-2
|
||||
tests/openpgp/plain-3
|
||||
tests/openpgp/plain-large
|
||||
tests/openpgp/prepared.stamp
|
||||
tests/openpgp/pubring.gpg
|
||||
tests/openpgp/pubring.pkr
|
||||
tests/openpgp/secring.gpg
|
||||
tests/openpgp/secring.skr
|
||||
tests/pkits/ReadMe.txt
|
||||
tests/pkits/certpairs/
|
||||
tests/pkits/certs/
|
||||
tests/pkits/crls/
|
||||
tests/pkits/gpg-agent.conf
|
||||
tests/pkits/gpgsm.conf
|
||||
tests/pkits/inittests.stamp
|
||||
tests/pkits/pkcs12/
|
||||
tests/pkits/pkits.ldif
|
||||
tests/pkits/pkits.schema
|
||||
tests/pkits/policies.txt
|
||||
tests/pkits/smime/
|
||||
tests/pkits/testdir.stamp
|
||||
tests/pkits/trustlist.txt
|
||||
tests/private-keys-v1.d/
|
||||
tests/pubring.kbx
|
||||
tests/testdir.stamp
|
||||
tests/trustlist.txt
|
||||
tools/clean-sat
|
||||
tools/gpg-check-pattern
|
||||
tools/gpg-connect-agent
|
||||
tools/gpgconf
|
||||
tools/gpgkey2ssh
|
||||
tools/gpgparsemail
|
||||
tools/gpgsplit
|
||||
tools/make-dns-cert
|
||||
tools/mk-tdata
|
||||
tools/symcryptrun
|
||||
tools/watchgnupg
|
||||
tools/gpgtar
|
||||
g13/g13
|
||||
|
4
AUTHORS
4
AUTHORS
@ -11,6 +11,9 @@ Authors
|
||||
|
||||
Ales Nyakhaychyk <nyakhaychyk@i1fn.linux.by> Translations [be]
|
||||
|
||||
Andrey Jivsov <openpgp@brainhub.org> Assigns past and future changes for ECC.
|
||||
(g10/ecdh.c. other changes to support ECC)
|
||||
|
||||
Birger Langkjer <birger.langkjer@image.dk> Translations [da]
|
||||
|
||||
Maxim Britov <maxim.britov@gmail.com> Translations [ru]
|
||||
@ -174,4 +177,3 @@ name gpg2keys_*.
|
||||
This file is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
2011-02-01 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac (HAVE_GCRY_PK_GET_CURVE): Define if availabale.
|
||||
|
||||
2011-01-20 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac (AC_CONFIG_FILES): Remove keyserver/.
|
||||
@ -8,6 +12,11 @@
|
||||
(NAME_OF_INSTALLED_GPG): New ac_define.
|
||||
* autogen.sh [--build-w32ce]: Use --enable-gpg2-is-gpg.
|
||||
|
||||
2011-01-21 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac: Need Libgcrypt 1.4.6 due to AESWRAP.
|
||||
(HAVE_GCRY_PK_ECDH): Add new test.
|
||||
|
||||
2011-01-03 Werner Koch <wk@g10code.com>
|
||||
|
||||
* README.SVN: Rename to README.GIT.
|
||||
|
4
NEWS
4
NEWS
@ -20,6 +20,8 @@ Noteworthy changes in version 2.1.0beta2 (unreleased)
|
||||
* Dirmngr has taken over the function of the keyserver helpers. Thus
|
||||
we now have a specified direct interface to keyservers via Dirmngr.
|
||||
|
||||
* ECC support for GPG as described by draft-jivsov-openpgp-ecc-06.txt.
|
||||
|
||||
|
||||
Noteworthy changes in version 2.1.0beta1 (2010-10-26)
|
||||
-----------------------------------------------------
|
||||
@ -794,7 +796,7 @@ Noteworthy changes in version 1.9.0 (2003-08-05)
|
||||
|
||||
|
||||
Copyright 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
2008, 2009 Free Software Foundation, Inc.
|
||||
2008, 2009, 2010, 2011 Free Software Foundation, Inc.
|
||||
|
||||
This file is free software; as a special exception the author gives
|
||||
unlimited permission to copy and/or distribute it, with or without
|
||||
|
@ -1,7 +1,42 @@
|
||||
2011-02-03 Werner Koch <wk@g10code.com>
|
||||
|
||||
* protect.c (protect_info): Support ECC algos.
|
||||
|
||||
* pksign.c (do_encode_dsa): Map public key algo number. Extend
|
||||
DSA size check for ECDSA.
|
||||
|
||||
* gpg-agent.c: Include cipher.h.
|
||||
(map_pk_openpgp_to_gcry): New.
|
||||
|
||||
* findkey.c (key_parms_from_sexp): Support ECDH.
|
||||
|
||||
* cvt-openpgp.c (get_keygrip): Support ECC algorithms.
|
||||
(convert_secret_key): Ditto.
|
||||
(do_unprotect): Ditto.
|
||||
|
||||
2011-02-02 Werner Koch <wk@g10code.com>
|
||||
|
||||
* cvt-openpgp.c (convert_secret_key): Remove algo mapping.
|
||||
|
||||
2011-01-31 Werner Koch <wk@g10code.com>
|
||||
|
||||
* cvt-openpgp.c (convert_to_openpgp): Adjust to reverted Libgcrypt
|
||||
ABI.
|
||||
|
||||
* protect.c (protect_info): Adjust ECDSA and ECDH parameter names.
|
||||
Add "ecc".
|
||||
* findkey.c (key_parms_from_sexp): Ditto.
|
||||
|
||||
2011-01-19 Werner Koch <wk@g10code.com>
|
||||
|
||||
* trustlist.c (read_one_trustfile): Also chop an CR.
|
||||
|
||||
2011-01-21 Werner Koch <wk@g10code.com>
|
||||
|
||||
* pksign.c (do_encode_dsa): Compare MDLEN to bytes.
|
||||
|
||||
* cvt-openpgp.c (GCRY_PK_ECDH) [!HAVE_GCRY_PK_ECDH]: New.
|
||||
|
||||
2010-12-02 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpg-agent.c (CHECK_OWN_SOCKET_INTERVAL) [W32CE]: Set to 60
|
||||
|
@ -215,6 +215,7 @@ const char *get_agent_ssh_socket_name (void);
|
||||
void *get_agent_scd_notify_event (void);
|
||||
#endif
|
||||
void agent_sighup_action (void);
|
||||
int map_pk_openpgp_to_gcry (int openpgp_algo);
|
||||
|
||||
/*-- command.c --*/
|
||||
gpg_error_t agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid);
|
||||
|
@ -28,6 +28,13 @@
|
||||
#include "i18n.h"
|
||||
#include "cvt-openpgp.h"
|
||||
|
||||
/* Macros for compatibility with older libgcrypt versions. */
|
||||
#ifndef HAVE_GCRY_PK_ECDSA
|
||||
# define GCRY_PK_ECDH 302
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/* Helper to pass data via the callback to do_unprotect. */
|
||||
struct try_do_unprotect_arg_s
|
||||
@ -80,6 +87,14 @@ 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(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))",
|
||||
pkey[0], pkey[1], pkey[2], pkey[3], pkey[4],
|
||||
pkey[5]);
|
||||
break;
|
||||
|
||||
default:
|
||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
break;
|
||||
@ -94,7 +109,8 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
|
||||
|
||||
|
||||
/* Convert a secret key given as algorithm id and an array of key
|
||||
parameters into our s-expression based format. */
|
||||
parameters into our s-expression based format. Note that
|
||||
PUBKEY_ALGO has an gcrypt algorithm number. */
|
||||
static gpg_error_t
|
||||
convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
|
||||
{
|
||||
@ -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:
|
||||
case GCRY_PK_ECDH:
|
||||
/* Although our code would work with "ecc" we explicitly use
|
||||
"ecdh" or "ecdsa" to implicitly set the key capabilities. */
|
||||
err = gcry_sexp_build (&s_skey, NULL,
|
||||
"(private-key(%s(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)"
|
||||
"(d%m)))",
|
||||
pubkey_algo == GCRY_PK_ECDSA?"ecdsa":"ecdh",
|
||||
skey[0], skey[1], skey[2], skey[3], skey[4],
|
||||
skey[5], skey[6]);
|
||||
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);
|
||||
@ -1008,6 +1037,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
||||
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_ECDH: algoname = "ecdh"; npkey = 6; elems = "pabgnqd"; break;
|
||||
default: algoname = ""; npkey = 0; elems = NULL; break;
|
||||
}
|
||||
assert (!elems || strlen (elems) < DIM (array) );
|
||||
@ -1037,7 +1067,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);
|
||||
|
||||
@ -1088,4 +1118,3 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
|
||||
|
||||
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 = "pabgnq";
|
||||
}
|
||||
else if (n==4 && !memcmp (name, "ecdh", 4))
|
||||
{
|
||||
algoname = "ecdh";
|
||||
elems = "pabgnq";
|
||||
}
|
||||
else if (n==3 && !memcmp (name, "elg", 3))
|
||||
{
|
||||
algoname = "elg";
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "gc-opt-flags.h"
|
||||
#include "exechelp.h"
|
||||
#include "asshelp.h"
|
||||
#include "../include/cipher.h" /* for PUBKEY_ALGO_ECDSA, PUBKEY_ALGO_ECDH */
|
||||
|
||||
enum cmd_and_opt_values
|
||||
{ aNull = 0,
|
||||
@ -2301,3 +2302,12 @@ check_for_running_agent (int silent, int mode)
|
||||
assuan_release (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: it is also in misc, which is not linked with the agent */
|
||||
/* FIXME: The agent should not know about openpgp internals - weel
|
||||
except for some stuff in cvt-openpgp. */
|
||||
int
|
||||
map_pk_openpgp_to_gcry (int algo)
|
||||
{
|
||||
return (algo==PUBKEY_ALGO_ECDSA ? GCRY_PK_ECDSA : (algo==PUBKEY_ALGO_ECDH ? GCRY_PK_ECDH : algo));
|
||||
}
|
||||
|
@ -113,18 +113,21 @@ get_dsa_qbits (gcry_sexp_t key)
|
||||
|
||||
/* Encode a message digest for use with an DSA algorithm. */
|
||||
static gpg_error_t
|
||||
do_encode_dsa (const byte * md, size_t mdlen, int dsaalgo, gcry_sexp_t pkey,
|
||||
do_encode_dsa (const byte *md, size_t mdlen, int dsaalgo, gcry_sexp_t pkey,
|
||||
gcry_sexp_t *r_hash)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gcry_sexp_t hash;
|
||||
unsigned int qbits;
|
||||
int pkalgo;
|
||||
|
||||
*r_hash = NULL;
|
||||
|
||||
if (dsaalgo == GCRY_PK_ECDSA)
|
||||
pkalgo = map_pk_openpgp_to_gcry (dsaalgo);
|
||||
|
||||
if (pkalgo == GCRY_PK_ECDSA)
|
||||
qbits = gcry_pk_get_nbits (pkey);
|
||||
else if (dsaalgo == GCRY_PK_DSA)
|
||||
else if (pkalgo == GCRY_PK_DSA)
|
||||
qbits = get_dsa_qbits (pkey);
|
||||
else
|
||||
return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
|
||||
@ -143,20 +146,28 @@ do_encode_dsa (const byte * md, size_t mdlen, int dsaalgo, gcry_sexp_t pkey,
|
||||
if (qbits < 160)
|
||||
{
|
||||
log_error (_("%s key uses an unsafe (%u bit) hash\n"),
|
||||
gcry_pk_algo_name (dsaalgo), qbits);
|
||||
gcry_pk_algo_name (pkalgo), qbits);
|
||||
return gpg_error (GPG_ERR_INV_LENGTH);
|
||||
}
|
||||
|
||||
/* Check if we're too short. Too long is safe as we'll
|
||||
automatically left-truncate. */
|
||||
if (mdlen < qbits/8)
|
||||
* automatically left-truncate.
|
||||
*
|
||||
* This check 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 is really a bug for
|
||||
* ECDSA 521 as the only hash that matches it is SHA 512, but 512 <
|
||||
* 521 ).
|
||||
*/
|
||||
if (mdlen < ((pkalgo==GCRY_PK_ECDSA && qbits > 521) ? 512 : qbits)/8)
|
||||
{
|
||||
log_error (_("a %zu bit hash is not valid for a %u bit %s key\n"),
|
||||
mdlen*8,
|
||||
gcry_pk_get_nbits (pkey),
|
||||
gcry_pk_algo_name (dsaalgo));
|
||||
gcry_pk_algo_name (pkalgo));
|
||||
/* FIXME: we need to check the requirements for ECDSA. */
|
||||
if (mdlen < 20 || dsaalgo == GCRY_PK_DSA)
|
||||
if (mdlen < 20 || pkalgo == GCRY_PK_DSA)
|
||||
return gpg_error (GPG_ERR_INV_LENGTH);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* protect.c - Un/Protect a secret key
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002,
|
||||
* 2003, 2007, 2009 Free Software Foundation, Inc.
|
||||
* 2003, 2007, 2009, 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -43,7 +43,7 @@
|
||||
|
||||
|
||||
/* A table containing the information needed to create a protected
|
||||
private key */
|
||||
private key. */
|
||||
static struct {
|
||||
const char *algo;
|
||||
const char *parmlist;
|
||||
@ -52,6 +52,9 @@ static struct {
|
||||
{ "rsa", "nedpqu", 2, 5 },
|
||||
{ "dsa", "pqgyx", 4, 4 },
|
||||
{ "elg", "pgyx", 3, 3 },
|
||||
{ "ecdsa","pabgnqd", 6, 6 },
|
||||
{ "ecdh", "pabgnqd", 6, 6 },
|
||||
{ "ecc", "pabgnqd", 6, 6 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -488,7 +491,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
|
||||
depth--;
|
||||
hash_end = s;
|
||||
s++;
|
||||
/* skip to the end of the S-exp */
|
||||
/* Skip to the end of the S-expression. */
|
||||
assert (depth == 1);
|
||||
rc = sskip (&s, &depth);
|
||||
if (rc)
|
||||
@ -1347,4 +1350,3 @@ parse_shadow_info (const unsigned char *shadow_info,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
2011-01-31 Werner Koch <wk@g10code.com>
|
||||
|
||||
* openpgp-oid.c: New.
|
||||
* t-openpgp-oid.c: New.
|
||||
|
||||
2011-01-20 Werner Koch <wk@g10code.com>
|
||||
|
||||
Fix bug#1313.
|
||||
|
@ -90,6 +90,7 @@ common_sources = \
|
||||
localename.c \
|
||||
session-env.c session-env.h \
|
||||
userids.c userids.h \
|
||||
openpgp-oid.c \
|
||||
helpfile.c
|
||||
|
||||
# To make the code easier to read we have split home some code into
|
||||
@ -160,7 +161,7 @@ if HAVE_W32_SYSTEM
|
||||
jnlib_tests += t-w32-reg
|
||||
endif
|
||||
module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil \
|
||||
t-session-env
|
||||
t-session-env t-openpgp-oid
|
||||
if !HAVE_W32CE_SYSTEM
|
||||
module_tests += t-exechelp
|
||||
endif
|
||||
@ -192,6 +193,7 @@ t_sexputil_LDADD = $(t_common_ldadd)
|
||||
t_b64_LDADD = $(t_common_ldadd)
|
||||
t_exechelp_LDADD = $(t_common_ldadd)
|
||||
t_session_env_LDADD = $(t_common_ldadd)
|
||||
t_openpgp_oid_LDADD = $(t_common_ldadd)
|
||||
|
||||
|
||||
|
||||
|
@ -244,6 +244,3 @@ hex2str_alloc (const char *hexstring, size_t *r_count)
|
||||
BUG ();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
227
common/openpgp-oid.c
Normal file
227
common/openpgp-oid.c
Normal file
@ -0,0 +1,227 @@
|
||||
/* openpgp-oids.c - OID helper for OpenPGP
|
||||
* Copyright (C) 2011 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 <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
|
||||
/* Helper for openpgp_oid_from_str. */
|
||||
static size_t
|
||||
make_flagged_int (unsigned long value, char *buf, size_t buflen)
|
||||
{
|
||||
int more = 0;
|
||||
int shift;
|
||||
|
||||
/* fixme: figure out the number of bits in an ulong and start with
|
||||
that value as shift (after making it a multiple of 7) a more
|
||||
straigtforward implementation is to do it in reverse order using
|
||||
a temporary buffer - saves a lot of compares */
|
||||
for (more=0, shift=28; shift > 0; shift -= 7)
|
||||
{
|
||||
if (more || value >= (1<<shift))
|
||||
{
|
||||
buf[buflen++] = 0x80 | (value >> shift);
|
||||
value -= (value >> shift) << shift;
|
||||
more = 1;
|
||||
}
|
||||
}
|
||||
buf[buflen++] = value;
|
||||
return buflen;
|
||||
}
|
||||
|
||||
|
||||
/* Convert the OID given in dotted decimal form in STRING to an DER
|
||||
* encoding and store it as an opaque value at R_MPI. The format of
|
||||
* the DER encoded is not a regular ASN.1 object but the modified
|
||||
* format as used by OpenPGP for the ECC curve description. On error
|
||||
* the function returns and error code an NULL is stored at R_BUG.
|
||||
* Note that scanning STRING stops at the first white space
|
||||
* character. */
|
||||
gpg_error_t
|
||||
openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi)
|
||||
{
|
||||
unsigned char *buf;
|
||||
size_t buflen;
|
||||
unsigned long val1, val;
|
||||
const char *endp;
|
||||
int arcno;
|
||||
|
||||
*r_mpi = NULL;
|
||||
|
||||
if (!string || !*string)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
/* We can safely assume that the encoded OID is shorter than the string. */
|
||||
buf = xtrymalloc (1 + strlen (string) + 2);
|
||||
if (!buf)
|
||||
return gpg_error_from_syserror ();
|
||||
/* Save the first byte for the length. */
|
||||
buflen = 1;
|
||||
|
||||
val1 = 0; /* Avoid compiler warning. */
|
||||
arcno = 0;
|
||||
do {
|
||||
arcno++;
|
||||
val = strtoul (string, (char**)&endp, 10);
|
||||
if (!digitp (string) || !(*endp == '.' || !*endp))
|
||||
{
|
||||
xfree (buf);
|
||||
return gpg_error (GPG_ERR_INV_OID_STRING);
|
||||
}
|
||||
if (*endp == '.')
|
||||
string = endp+1;
|
||||
|
||||
if (arcno == 1)
|
||||
{
|
||||
if (val > 2)
|
||||
break; /* Not allowed, error catched below. */
|
||||
val1 = val;
|
||||
}
|
||||
else if (arcno == 2)
|
||||
{ /* Need to combine the first two arcs in one octet. */
|
||||
if (val1 < 2)
|
||||
{
|
||||
if (val > 39)
|
||||
{
|
||||
xfree (buf);
|
||||
return gpg_error (GPG_ERR_INV_OID_STRING);
|
||||
}
|
||||
buf[buflen++] = val1*40 + val;
|
||||
}
|
||||
else
|
||||
{
|
||||
val += 80;
|
||||
buflen = make_flagged_int (val, buf, buflen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buflen = make_flagged_int (val, buf, buflen);
|
||||
}
|
||||
} while (*endp == '.');
|
||||
|
||||
if (arcno == 1 || buflen < 2 || buflen > 254 )
|
||||
{ /* It is not possible to encode only the first arc. */
|
||||
xfree (buf);
|
||||
return gpg_error (GPG_ERR_INV_OID_STRING);
|
||||
}
|
||||
|
||||
*buf = buflen - 1;
|
||||
*r_mpi = gcry_mpi_set_opaque (NULL, buf, buflen * 8);
|
||||
if (!*r_mpi)
|
||||
{
|
||||
xfree (buf);
|
||||
return gpg_error_from_syserror ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return a malloced string represenation of the OID in the opaque MPI
|
||||
A. In case of an error NULL is returned and ERRNO is set. */
|
||||
char *
|
||||
openpgp_oid_to_str (gcry_mpi_t a)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
size_t length;
|
||||
char *string, *p;
|
||||
int n = 0;
|
||||
unsigned long val, valmask;
|
||||
|
||||
valmask = (unsigned long)0xfe << (8 * (sizeof (valmask) - 1));
|
||||
|
||||
if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
gpg_err_set_errno (EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = gcry_mpi_get_opaque (a, &length);
|
||||
length = (length+7)/8;
|
||||
|
||||
/* The first bytes gives the length; check consistency. */
|
||||
if (!length || buf[0] != length -1)
|
||||
{
|
||||
gpg_err_set_errno (EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
/* Skip length byte. */
|
||||
length--;
|
||||
buf++;
|
||||
|
||||
/* To calculate the length of the string we can safely assume an
|
||||
upper limit of 3 decimal characters per byte. Two extra bytes
|
||||
account for the special first octect */
|
||||
string = p = xtrymalloc (length*(1+3)+2+1);
|
||||
if (!string)
|
||||
return NULL;
|
||||
if (!buf || !length)
|
||||
{
|
||||
*p = 0;
|
||||
return string;
|
||||
}
|
||||
|
||||
if (buf[0] < 40)
|
||||
p += sprintf (p, "0.%d", buf[n]);
|
||||
else if (buf[0] < 80)
|
||||
p += sprintf (p, "1.%d", buf[n]-40);
|
||||
else {
|
||||
val = buf[n] & 0x7f;
|
||||
while ( (buf[n]&0x80) && ++n < length )
|
||||
{
|
||||
if ( (val & valmask) )
|
||||
goto badoid; /* Overflow. */
|
||||
val <<= 7;
|
||||
val |= buf[n] & 0x7f;
|
||||
}
|
||||
val -= 80;
|
||||
sprintf (p, "2.%lu", val);
|
||||
p += strlen (p);
|
||||
}
|
||||
for (n++; n < length; n++)
|
||||
{
|
||||
val = buf[n] & 0x7f;
|
||||
while ( (buf[n]&0x80) && ++n < length )
|
||||
{
|
||||
if ( (val & valmask) )
|
||||
goto badoid; /* Overflow. */
|
||||
val <<= 7;
|
||||
val |= buf[n] & 0x7f;
|
||||
}
|
||||
sprintf (p, ".%lu", val);
|
||||
p += strlen (p);
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
return string;
|
||||
|
||||
badoid:
|
||||
/* Return a special OID (gnu.gnupg.badoid) to indicate the error
|
||||
case. The OID is broken and thus we return one which can't do
|
||||
any harm. Formally this does not need to be a bad OID but an OID
|
||||
with an arc that can't be represented in a 32 bit word is more
|
||||
than likely corrupt. */
|
||||
xfree (string);
|
||||
return xtrystrdup ("1.3.6.1.4.1.11591.2.12242973");
|
||||
}
|
148
common/t-openpgp-oid.c
Normal file
148
common/t-openpgp-oid.c
Normal file
@ -0,0 +1,148 @@
|
||||
/* t-openpgp-oid.c - Module test for openpgp-oid.c
|
||||
* Copyright (C) 2011 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 <assert.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#define pass() do { ; } while(0)
|
||||
#define fail(a,e) \
|
||||
do { fprintf (stderr, "%s:%d: test %d failed (%s)\n", \
|
||||
__FILE__,__LINE__, (a), gpg_strerror (e)); \
|
||||
exit (1); \
|
||||
} while(0)
|
||||
|
||||
|
||||
static void
|
||||
test_openpgp_oid_from_str (void)
|
||||
{
|
||||
static char *sample_oids[] =
|
||||
{
|
||||
"0.0",
|
||||
"1.0",
|
||||
"1.2.3",
|
||||
"1.2.840.10045.3.1.7",
|
||||
"1.3.132.0.34",
|
||||
"1.3.132.0.35",
|
||||
NULL
|
||||
};
|
||||
gpg_error_t err;
|
||||
gcry_mpi_t a;
|
||||
int idx;
|
||||
char *string;
|
||||
unsigned char *p;
|
||||
unsigned int nbits;
|
||||
size_t length;
|
||||
|
||||
err = openpgp_oid_from_str ("", &a);
|
||||
if (gpg_err_code (err) != GPG_ERR_INV_VALUE)
|
||||
fail (0, err);
|
||||
gcry_mpi_release (a);
|
||||
|
||||
err = openpgp_oid_from_str (".", &a);
|
||||
if (gpg_err_code (err) != GPG_ERR_INV_OID_STRING)
|
||||
fail (0, err);
|
||||
gcry_mpi_release (a);
|
||||
|
||||
err = openpgp_oid_from_str ("0", &a);
|
||||
if (gpg_err_code (err) != GPG_ERR_INV_OID_STRING)
|
||||
fail (0, err);
|
||||
gcry_mpi_release (a);
|
||||
|
||||
for (idx=0; sample_oids[idx]; idx++)
|
||||
{
|
||||
err = openpgp_oid_from_str (sample_oids[idx], &a);
|
||||
if (err)
|
||||
fail (idx, err);
|
||||
|
||||
string = openpgp_oid_to_str (a);
|
||||
if (!string)
|
||||
fail (idx, gpg_error_from_syserror ());
|
||||
if (strcmp (string, sample_oids[idx]))
|
||||
fail (idx, 0);
|
||||
xfree (string);
|
||||
|
||||
p = gcry_mpi_get_opaque (a, &nbits);
|
||||
length = (nbits+7)/8;
|
||||
if (!p || !length || p[0] != length - 1)
|
||||
fail (idx, 0);
|
||||
|
||||
gcry_mpi_release (a);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_openpgp_oid_to_str (void)
|
||||
{
|
||||
static struct {
|
||||
const char *string;
|
||||
unsigned char der[10];
|
||||
} samples[] = {
|
||||
{ "1.2.840.10045.3.1.7",
|
||||
{8, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 }},
|
||||
|
||||
{ "1.3.132.0.34",
|
||||
{5, 0x2B, 0x81, 0x04, 0x00, 0x22 }},
|
||||
|
||||
{ "1.3.132.0.35",
|
||||
{ 5, 0x2B, 0x81, 0x04, 0x00, 0x23 }},
|
||||
|
||||
{ NULL }};
|
||||
gcry_mpi_t a;
|
||||
int idx;
|
||||
char *string;
|
||||
unsigned char *p;
|
||||
|
||||
for (idx=0; samples[idx].string; idx++)
|
||||
{
|
||||
p = xmalloc (samples[idx].der[0]+1);
|
||||
memcpy (p, samples[idx].der, samples[idx].der[0]+1);
|
||||
a = gcry_mpi_set_opaque (NULL, p, (samples[idx].der[0]+1)*8);
|
||||
if (!a)
|
||||
fail (idx, gpg_error_from_syserror ());
|
||||
|
||||
string = openpgp_oid_to_str (a);
|
||||
if (!string)
|
||||
fail (idx, gpg_error_from_syserror ());
|
||||
if (strcmp (string, samples[idx].string))
|
||||
fail (idx, 0);
|
||||
xfree (string);
|
||||
gcry_mpi_release (a);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
test_openpgp_oid_from_str ();
|
||||
test_openpgp_oid_to_str ();
|
||||
|
||||
return 0;
|
||||
}
|
@ -42,6 +42,12 @@
|
||||
#ifndef GPG_ERR_FULLY_CANCELED
|
||||
#define GPG_ERR_FULLY_CANCELED 198
|
||||
#endif
|
||||
#ifndef GPG_ERR_INV_CURVE
|
||||
#define GPG_ERR_INV_CURVE 187
|
||||
#endif
|
||||
#ifndef GPG_ERR_UNKNOWN_CURVE
|
||||
#define GPG_ERR_UNKNOWN_CURVE 188
|
||||
#endif
|
||||
|
||||
|
||||
/* Hash function used with libksba. */
|
||||
@ -209,6 +215,11 @@ char *percent_unescape (const char *string, int nulrepl);
|
||||
size_t percent_plus_unescape_inplace (char *string, int nulrepl);
|
||||
size_t percent_unescape_inplace (char *string, int nulrepl);
|
||||
|
||||
/*-- openpgp-oid.c --*/
|
||||
gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi);
|
||||
char *openpgp_oid_to_str (gcry_mpi_t a);
|
||||
|
||||
|
||||
|
||||
/*-- homedir.c --*/
|
||||
const char *standard_homedir (void);
|
||||
|
34
configure.ac
34
configure.ac
@ -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.4.6
|
||||
|
||||
NEED_LIBASSUAN_API=2
|
||||
NEED_LIBASSUAN_VERSION=2.0.0
|
||||
@ -742,6 +742,36 @@ AM_PATH_GPG_ERROR("$NEED_GPG_ERROR_VERSION",
|
||||
AM_PATH_LIBGCRYPT("$NEED_LIBGCRYPT_API:$NEED_LIBGCRYPT_VERSION",
|
||||
have_libgcrypt=yes,have_libgcrypt=no)
|
||||
|
||||
# fixme: We can remove the next two checks if we require libgcrypt 1.5.
|
||||
AC_CACHE_CHECK([whether Libgcrypt support ECDH], gnupg_cv_gcry_pk_ecdh,
|
||||
[ _gnupg_gcry_save_cflags=$CFLAGS
|
||||
CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS"
|
||||
AC_TRY_COMPILE(
|
||||
[#include <gcrypt.h>],
|
||||
[ return GCRY_PK_ECDH; ],
|
||||
gnupg_cv_gcry_pk_ecdh=yes,
|
||||
gnupg_cv_gcry_pk_ecdh=no)
|
||||
CFLAGS=$_gnupg_gcry_save_cflags])
|
||||
if test "$gnupg_cv_gcry_pk_ecdh" = yes; then
|
||||
AC_DEFINE([HAVE_GCRY_PK_ECDH], 1,
|
||||
[Define if gcrypt.h has the enum value for ECDH.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether Libgcrypt has gcry_pk_get_curve],
|
||||
gnupg_cv_gcry_pk_get_curve,
|
||||
[ _gnupg_gcry_save_cflags=$CFLAGS
|
||||
CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS"
|
||||
AC_TRY_COMPILE(
|
||||
[#include <gcrypt.h>],
|
||||
[ return gcry_pk_get_curve (NULL, 0, NULL); ],
|
||||
gnupg_cv_gcry_pk_get_curve=yes,
|
||||
gnupg_cv_gcry_pk_get_curve=no)
|
||||
CFLAGS=$_gnupg_gcry_save_cflags])
|
||||
if test "$gnupg_cv_gcry_pk_get_curve" = yes; then
|
||||
AC_DEFINE([HAVE_GCRY_PK_GET_CURVE], 1,
|
||||
[Define if gcrypt.h has gcry_pk_get_curve.])
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# libassuan is used for IPC
|
||||
@ -1484,7 +1514,7 @@ AC_ARG_ENABLE(optimization,
|
||||
AC_HELP_STRING([--disable-optimization],
|
||||
[disable compiler optimization]),
|
||||
[if test $enableval = no ; then
|
||||
CFLAGS=`echo $CFLAGS | sed 's/-O[[0-9]]//'`
|
||||
CFLAGS=`echo $CFLAGS | sed s/-O[[1-9]]\ /-O0\ /g`
|
||||
fi])
|
||||
|
||||
#
|
||||
|
@ -62,7 +62,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 #FIXME: Test for liblber first.
|
||||
endif
|
||||
dirmngr_LDFLAGS = $(extra_bin_ldflags)
|
||||
|
||||
|
139
g10/ChangeLog
139
g10/ChangeLog
@ -1,7 +1,87 @@
|
||||
2011-02-03 Werner Koch <wk@g10code.com>
|
||||
|
||||
Finished ECC integration.
|
||||
Wrote change description for 2011-01-13.
|
||||
|
||||
2011-02-02 Werner Koch <wk@g10code.com>
|
||||
|
||||
* encrypt.c (write_pubkey_enc_from_list): Don't compute the
|
||||
fingerprint.
|
||||
* pkglue.c (pk_encrypt): Replace PK_FP by PK and compute the
|
||||
fingerprint only when needed.
|
||||
* pkglue.h: Include packet.h.
|
||||
|
||||
* import.c (transfer_secret_keys): Make sure keyids are available.
|
||||
|
||||
* keyid.c (hash_public_key): Adjust for the ECC case.
|
||||
|
||||
2011-02-01 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpg.c (main): Call setup_libgcrypt_logging.
|
||||
|
||||
* import.c (transfer_secret_keys): Implement ECC case.
|
||||
(one_mpi_from_pkey): New.
|
||||
* export.c (transfer_format_to_openpgp): Ditto.
|
||||
* keygen.c (gpg_curve_to_oid): New.
|
||||
(ecckey_from_sexp): Factor curve name mapping out to new function.
|
||||
|
||||
2011-01-31 Werner Koch <wk@g10code.com>
|
||||
|
||||
* ecdh.c (pk_ecdh_encrypt_with_shared_point): Return an opaque MPI.
|
||||
|
||||
* build-packet.c (mpi_write): Rename to gpg_mpi_write and make global.
|
||||
|
||||
2011-01-30 Werner Koch <wk@g10code.com>
|
||||
|
||||
* keyid.c (keygrip_from_pk): Adjust ECC cases.
|
||||
* pkglue.c (pk_verify): Ditto.
|
||||
|
||||
* parse-packet.c (parse_key): Simply ECC case.
|
||||
(parse_pubkeyenc): Ditto.
|
||||
|
||||
* misc.c (pubkey_get_npkey): Special case ECC.
|
||||
(pubkey_get_nskey): Ditto.
|
||||
(mpi_print): Support printing of opaque values.
|
||||
(openpgp_oid_to_str): New.
|
||||
(pubkey_nbits): For ECC pass curve parameter.
|
||||
|
||||
* ecdh.c (pk_ecdh_default_params): Change to return an opaque MPI.
|
||||
|
||||
* build-packet.c (do_key): Automatically handle real and opaque
|
||||
key parameters.
|
||||
(write_fake_data): Return an error code.
|
||||
(mpi_write): Support writing opaque MPIs.
|
||||
(do_pubkey_enc): Simplify ECC handling.
|
||||
|
||||
2011-01-28 Werner Koch <wk@g10code.com>
|
||||
|
||||
* keygen.c (gen_ecc): Rewrite. Select a named curve and create a
|
||||
keyspec based on that.
|
||||
(pk_ecc_build_key_params): Remove.
|
||||
(get_parameter_algo): Map algo number.
|
||||
(ecckey_from_sexp): New.
|
||||
* misc.c (map_pk_gcry_to_openpgp): New.
|
||||
|
||||
2011-01-25 Werner Koch <wk@g10code.com>
|
||||
|
||||
* ecdh.c (pk_ecdh_default_params_to_mpi): Remove.
|
||||
(pk_ecdh_default_params): Rewrite. Factor KEK table out to ..
|
||||
(kek_params_table): .. here.
|
||||
(pk_ecdh_generate_ephemeral_key): New.
|
||||
(pk_ecdh_encrypt): Remove.
|
||||
(pk_ecdh_encrypt_with_shared_point): Make public.
|
||||
|
||||
* pubkey-enc.c (get_it): Fix assertion. Use GPG_ERR_WRONG_SECKEY
|
||||
instead of log_fatal. Add safety checks for NFRAME.
|
||||
|
||||
* keygen.c (pk_ecc_keypair_gen): Make static.
|
||||
(ask_keysize): Use proper rounding for ECC.
|
||||
(pk_ecc_build_key_params): Remove NBITSSTR.
|
||||
|
||||
2011-01-20 Werner Koch <wk@g10code.com>
|
||||
|
||||
* keyserver.c: Rewrite most stuff for use with dirmngr. Get rid
|
||||
of all spawn code. Work work pending.
|
||||
of all spawn code. More work pending.
|
||||
|
||||
* export.c (export_pubkeys_buffer): New.
|
||||
|
||||
@ -12,6 +92,57 @@
|
||||
* gpg.c: Include call-dirmngr.h.
|
||||
(gpg_deinit_default_ctrl): Call gpg_dirmngr_deinit_session_data.
|
||||
|
||||
2011-01-13 Andrey Jivsov <openpgp@brainhub.org> (wk)
|
||||
|
||||
Integrated ECC support. Below are the changes finally merged into
|
||||
the git master after some cleanup by wk until 2011-02-03.
|
||||
|
||||
* ecdh.c: New.
|
||||
|
||||
* sign.c (mpi_from_sexp): Remove.
|
||||
(match_dsa_hash): Uses SHA-512 for ECDSA with 521 bits.
|
||||
(hash_for): Support ECDSA.
|
||||
(make_keysig_packet): Ditto.
|
||||
|
||||
* seskey.c (encode_session_key): Add arg OPENPGP_PK_ALGO. Support
|
||||
ECDH.
|
||||
(encode_md_value): Map pkalgo. Extend size checks to ECDSA.
|
||||
|
||||
* pubkey-enc.c (get_it): Support ECDH.
|
||||
|
||||
* pkglue.c (mpi_from_sexp): Make global.
|
||||
(pk_verify, pk_encrypt, pk_check_secret_key): Support ECC.
|
||||
|
||||
* parse-packet.c (read_size_body): New.
|
||||
(parse_pubkeyenc): Support ECC.
|
||||
(parse_key): Ditto.
|
||||
|
||||
* misc.c (map_pk_openpgp_to_gcry, map_pk_gcry_to_openpgp): New.
|
||||
(openpgp_pk_test_algo, openpgp_pk_test_algo2): Map algo numbers.
|
||||
(openpgp_pk_algo_usage): Support ECDH and ECDSA.
|
||||
(openpgp_pk_algo_name): Simplify.
|
||||
(ecdsa_qbits_from_Q): New.
|
||||
|
||||
* mainproc.c (proc_pubkey_enc): Support ECC.
|
||||
|
||||
* keyid.c (pubkey_letter): Add 'E' and 'e'.
|
||||
(keygrip_from_pk): Supporf ECC.
|
||||
|
||||
* keygen.c: Include pkglue.h.
|
||||
(ask_algo): Add option 9 for ECDSA and ECDH.
|
||||
(ask_keysize): Support ECDSA and ECDH.
|
||||
(do_create): Ditto.
|
||||
(gen_ecc): New.
|
||||
(pk_ecc_build_key_params): New.
|
||||
|
||||
* getkey.c (cache_public_key): Support ECC.
|
||||
|
||||
* encrypt.c (write_pubkey_enc_from_list): Pass PK to PK_ENCRYPT
|
||||
and the pkalgo to encode_session_key.
|
||||
|
||||
* build-packet.c (do_key, do_pubkey_enc): Support ECC.
|
||||
(write_size_body_mpi): New.
|
||||
|
||||
2011-01-06 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpg.c (main): Use keyserver_spec_t.
|
||||
@ -20,6 +151,12 @@
|
||||
out to ../common/keyserver.h.
|
||||
(keyserver_spec_t): New.
|
||||
|
||||
2011-01-21 Werner Koch <wk@g10code.com>
|
||||
|
||||
* seskey.c (encode_md_value): Truncate the DSA hash again.
|
||||
|
||||
* misc.c (openpgp_pk_algo_name): Always use the gcrypt function.
|
||||
|
||||
2010-12-09 Werner Koch <wk@g10code.com>
|
||||
|
||||
* tdbio.c (tdbio_set_dbname) [W32CE]: Take care of missing errno.
|
||||
|
@ -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 \
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* build-packet.c - assemble packets and write them
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
|
||||
* 2006, 2010 Free Software Foundation, Inc.
|
||||
* 2006, 2010, 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -157,32 +157,41 @@ build_packet( IOBUF out, PACKET *pkt )
|
||||
/*
|
||||
* Write the mpi A to OUT.
|
||||
*/
|
||||
static int
|
||||
mpi_write (iobuf_t out, gcry_mpi_t a)
|
||||
gpg_error_t
|
||||
gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
|
||||
{
|
||||
char buffer[(MAX_EXTERN_MPI_BITS+7)/8+2]; /* 2 is for the mpi length. */
|
||||
size_t nbytes;
|
||||
int rc;
|
||||
|
||||
nbytes = DIM(buffer);
|
||||
rc = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a );
|
||||
if( !rc )
|
||||
rc = iobuf_write( out, buffer, nbytes );
|
||||
else if (gpg_err_code(rc) == GPG_ERR_TOO_SHORT )
|
||||
if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
log_info ("mpi too large (%u bits)\n", gcry_mpi_get_nbits (a));
|
||||
/* The buffer was too small. We better tell the user about the MPI. */
|
||||
rc = gpg_error (GPG_ERR_TOO_LARGE);
|
||||
size_t nbits;
|
||||
const void *p;
|
||||
|
||||
p = gcry_mpi_get_opaque (a, &nbits);
|
||||
rc = iobuf_write (out, p, (nbits+7)/8);
|
||||
}
|
||||
else
|
||||
{
|
||||
char buffer[(MAX_EXTERN_MPI_BITS+7)/8+2]; /* 2 is for the mpi length. */
|
||||
size_t nbytes;
|
||||
|
||||
nbytes = DIM(buffer);
|
||||
rc = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a );
|
||||
if( !rc )
|
||||
rc = iobuf_write( out, buffer, nbytes );
|
||||
else if (gpg_err_code(rc) == GPG_ERR_TOO_SHORT )
|
||||
{
|
||||
log_info ("mpi too large (%u bits)\n", gcry_mpi_get_nbits (a));
|
||||
/* The buffer was too small. We better tell the user about the MPI. */
|
||||
rc = gpg_error (GPG_ERR_TOO_LARGE);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* calculate the length of a packet described by PKT
|
||||
*/
|
||||
/* Calculate the length of a packet described by PKT. */
|
||||
u32
|
||||
calc_packet_length( PACKET *pkt )
|
||||
{
|
||||
@ -216,19 +225,20 @@ calc_packet_length( PACKET *pkt )
|
||||
return n;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
static gpg_error_t
|
||||
write_fake_data (IOBUF out, gcry_mpi_t a)
|
||||
{
|
||||
if (a)
|
||||
{
|
||||
unsigned int n;
|
||||
void *p;
|
||||
unsigned int n;
|
||||
void *p;
|
||||
|
||||
p = gcry_mpi_get_opaque ( a, &n );
|
||||
iobuf_write (out, p, (n+7)/8 );
|
||||
}
|
||||
if (!a)
|
||||
return 0;
|
||||
p = gcry_mpi_get_opaque ( a, &n);
|
||||
return iobuf_write (out, p, (n+7)/8 );
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
|
||||
{
|
||||
@ -290,10 +300,13 @@ 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;
|
||||
{
|
||||
err = gpg_mpi_write (a, pk->pkey[i]);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
||||
if (pk->seckey_info)
|
||||
{
|
||||
@ -384,7 +397,7 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|
||||
{
|
||||
/* Non-protected key. */
|
||||
for ( ; i < nskey; i++ )
|
||||
if ( (err = mpi_write (a, pk->pkey[i])))
|
||||
if ( (err = gpg_mpi_write (a, pk->pkey[i])))
|
||||
goto leave;
|
||||
write_16 (a, ski->csum );
|
||||
}
|
||||
@ -458,13 +471,14 @@ 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] );
|
||||
rc = gpg_mpi_write (a, enc->data[i]);
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
write_header(out, ctb, iobuf_get_temp_length(a) );
|
||||
rc = iobuf_write_temp( out, a );
|
||||
write_header (out, ctb, iobuf_get_temp_length(a) );
|
||||
rc = iobuf_write_temp (out, a);
|
||||
}
|
||||
iobuf_close(a);
|
||||
return rc;
|
||||
@ -1117,7 +1131,7 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
|
||||
if ( !n )
|
||||
write_fake_data( a, sig->data[0] );
|
||||
for (i=0; i < n && !rc ; i++ )
|
||||
rc = mpi_write(a, sig->data[i] );
|
||||
rc = gpg_mpi_write (a, sig->data[i] );
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
|
454
g10/ecdh.c
Normal file
454
g10/ecdh.c
Normal file
@ -0,0 +1,454 @@
|
||||
/* ecdh.c - ECDH public key operations used in public key glue code
|
||||
* Copyright (C) 2010, 2011 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"
|
||||
|
||||
/* A table with the default KEK parameters used by GnuPG. */
|
||||
static const struct
|
||||
{
|
||||
unsigned int qbits;
|
||||
int openpgp_hash_id; /* KEK digest algorithm. */
|
||||
int openpgp_cipher_id; /* KEK cipher algorithm. */
|
||||
} kek_params_table[] =
|
||||
/* Note: Must be sorted by ascending values for QBITS. */
|
||||
{
|
||||
{ 256, DIGEST_ALGO_SHA256, CIPHER_ALGO_AES },
|
||||
{ 384, DIGEST_ALGO_SHA384, CIPHER_ALGO_AES256 },
|
||||
|
||||
/* Note: 528 is 521 rounded to the 8 bit boundary */
|
||||
{ 528, DIGEST_ALGO_SHA512, CIPHER_ALGO_AES256 }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Return KEK parameters as an opaque MPI The caller must free the
|
||||
returned value. Returns NULL and sets ERRNO on error. */
|
||||
gcry_mpi_t
|
||||
pk_ecdh_default_params (unsigned int qbits)
|
||||
{
|
||||
byte *kek_params;
|
||||
int i;
|
||||
|
||||
kek_params = xtrymalloc (4);
|
||||
if (!kek_params)
|
||||
return NULL;
|
||||
kek_params[0] = 3; /* Number of bytes to follow. */
|
||||
kek_params[1] = 1; /* Version for KDF+AESWRAP. */
|
||||
|
||||
/* Search for matching KEK parameter. Defaults to the strongest
|
||||
possible choices. Performance is not an issue here, only
|
||||
interoperability. */
|
||||
for (i=0; i < DIM (kek_params_table); i++)
|
||||
{
|
||||
if (kek_params_table[i].qbits >= qbits
|
||||
|| i+1 == DIM (kek_params_table))
|
||||
{
|
||||
kek_params[2] = kek_params_table[i].openpgp_hash_id;
|
||||
kek_params[3] = kek_params_table[i].openpgp_cipher_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert (i < DIM (kek_params_table));
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ECDH KEK params are", kek_params, sizeof(kek_params) );
|
||||
|
||||
return gcry_mpi_set_opaque (NULL, kek_params, 4 * 8);
|
||||
}
|
||||
|
||||
|
||||
/* Encrypts/decrypts DATA using a key derived from the ECC shared
|
||||
point SHARED_MPI using the FIPS SP 800-56A compliant method
|
||||
key_derivation+key_wrapping. If IS_ENCRYPT is true the function
|
||||
encrypts; if false, it decrypts. On success the result is stored
|
||||
at R_RESULT; on failure NULL is stored at R_RESULT and an error
|
||||
code returned.
|
||||
|
||||
FIXME: explain PKEY and PK_FP.
|
||||
*/
|
||||
|
||||
/*
|
||||
TODO: memory leaks (x_secret).
|
||||
*/
|
||||
gpg_error_t
|
||||
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 *r_result)
|
||||
{
|
||||
gpg_error_t err;
|
||||
byte *secret_x;
|
||||
int secret_x_size;
|
||||
unsigned int nbits;
|
||||
const unsigned char *kek_params;
|
||||
size_t kek_params_size;
|
||||
int kdf_hash_algo;
|
||||
int kdf_encr_algo;
|
||||
unsigned char message[256];
|
||||
size_t message_size;
|
||||
|
||||
*r_result = NULL;
|
||||
|
||||
nbits = pubkey_nbits (PUBKEY_ALGO_ECDH, pkey);
|
||||
if (!nbits)
|
||||
return gpg_error (GPG_ERR_TOO_SHORT);
|
||||
|
||||
{
|
||||
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 = xtrymalloc_secure (nbytes);
|
||||
if (!secret_x)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
err = gcry_mpi_print (GCRYMPI_FMT_USG, secret_x, nbytes,
|
||||
&nbytes, shared_mpi);
|
||||
if (err)
|
||||
{
|
||||
xfree (secret_x);
|
||||
log_error ("ECDH ephemeral export of shared point failed: %s\n",
|
||||
gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
if (!gcry_mpi_get_flag (pkey[2], GCRYMPI_FLAG_OPAQUE))
|
||||
return GPG_ERR_BUG;
|
||||
kek_params = gcry_mpi_get_opaque (pkey[2], &nbits);
|
||||
kek_params_size = (nbits+7)/8;
|
||||
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ecdh KDF params:", kek_params, kek_params_size);
|
||||
|
||||
/* Expect 4 bytes 03 01 hash_alg symm_alg. */
|
||||
if (kek_params_size != 4 || kek_params[0] != 3 || kek_params[1] != 1)
|
||||
return GPG_ERR_BAD_PUBKEY;
|
||||
|
||||
kdf_hash_algo = kek_params[2];
|
||||
kdf_encr_algo = kek_params[3];
|
||||
|
||||
if (DBG_CIPHER)
|
||||
log_debug ("ecdh KDF algorithms %s+%s with aeswrap\n",
|
||||
openpgp_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 */
|
||||
err = gpg_mpi_write (obuf, pkey[0]);
|
||||
/* fixed-length field 2 */
|
||||
iobuf_put (obuf, PUBKEY_ALGO_ECDH);
|
||||
/* variable-length field 3, KDF params */
|
||||
err = (err ? err : gpg_mpi_write (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);
|
||||
|
||||
message_size = iobuf_temp_to_buffer (obuf, message, sizeof message);
|
||||
iobuf_close (obuf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if(DBG_CIPHER)
|
||||
log_printhex ("ecdh KDF message params are:", message, message_size);
|
||||
}
|
||||
|
||||
/* Derive a KEK (key wrapping key) using MESSAGE and SECRET_X. */
|
||||
{
|
||||
gcry_md_hd_t h;
|
||||
int old_size;
|
||||
|
||||
err = gcry_md_open (&h, kdf_hash_algo, 0);
|
||||
if(err)
|
||||
log_bug ("gcry_md_open failed for algo %d: %s",
|
||||
kdf_hash_algo, gpg_strerror (err));
|
||||
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, message, message_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) );
|
||||
|
||||
/* We could have allocated more, so clean the tail before returning. */
|
||||
memset( secret_x+secret_x_size, old_size-secret_x_size, 0 );
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ecdh KEK is:", secret_x, secret_x_size );
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
err = gcry_cipher_open (&hd, kdf_encr_algo, GCRY_CIPHER_MODE_AESWRAP, 0);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ecdh failed to initialize AESWRAP: %s\n",
|
||||
gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
err = gcry_cipher_setkey (hd, secret_x, secret_x_size);
|
||||
xfree( secret_x );
|
||||
if (err)
|
||||
{
|
||||
gcry_cipher_close (hd);
|
||||
log_error ("ecdh failed in gcry_cipher_setkey: %s\n",
|
||||
gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
data_buf_size = (gcry_mpi_get_nbits(data)+7)/8;
|
||||
assert ((data_buf_size & 7) == (is_encrypt ? 0 : 1));
|
||||
|
||||
data_buf = xtrymalloc_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. */
|
||||
err = gcry_mpi_print (GCRYMPI_FMT_USG, in,
|
||||
data_buf_size, &nbytes, data/*in*/);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ecdh failed to export DEK: %s\n", gpg_strerror (err));
|
||||
gcry_cipher_close (hd);
|
||||
xfree (data_buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ecdh encrypting :", in, data_buf_size );
|
||||
|
||||
err = 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 (err)
|
||||
{
|
||||
log_error ("ecdh failed in gcry_cipher_encrypt: %s\n",
|
||||
gpg_strerror (err));
|
||||
xfree (data_buf);
|
||||
return err;
|
||||
}
|
||||
data_buf[0] = data_buf_size+8;
|
||||
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ecdh encrypted to:", data_buf+1, data_buf[0] );
|
||||
|
||||
result = gcry_mpi_set_opaque (NULL, data_buf, 8 * (1+data_buf[0]));
|
||||
if (!result)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
xfree (data_buf);
|
||||
log_error ("ecdh failed to create an MPI: %s\n",
|
||||
gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
*r_result = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte *in;
|
||||
const void *p;
|
||||
|
||||
p = gcry_mpi_get_opaque (data, &nbits);
|
||||
nbytes = (nbits+7)/8;
|
||||
if (!p || nbytes > data_buf_size || !nbytes)
|
||||
{
|
||||
xfree (data_buf);
|
||||
return GPG_ERR_BAD_MPI;
|
||||
}
|
||||
memcpy (data_buf, p, nbytes);
|
||||
if (data_buf[0] != nbytes-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);
|
||||
|
||||
err = gcry_cipher_decrypt (hd, in, data_buf_size, data_buf+1,
|
||||
data_buf_size);
|
||||
gcry_cipher_close (hd);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ecdh failed in gcry_cipher_decrypt: %s\n",
|
||||
gpg_strerror (err));
|
||||
xfree (data_buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
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; */
|
||||
/* } */
|
||||
|
||||
err = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, in, data_buf_size, NULL);
|
||||
xfree (data_buf);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ecdh failed to create a plain text MPI: %s\n",
|
||||
gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
*r_result = result;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static gcry_mpi_t
|
||||
gen_k (unsigned nbits)
|
||||
{
|
||||
gcry_mpi_t k;
|
||||
|
||||
k = gcry_mpi_snew (nbits);
|
||||
if (DBG_CIPHER)
|
||||
log_debug ("choosing a random k of %u bits\n", nbits);
|
||||
|
||||
gcry_mpi_randomize (k, nbits-1, GCRY_STRONG_RANDOM);
|
||||
|
||||
if (DBG_CIPHER)
|
||||
{
|
||||
unsigned char *buffer;
|
||||
if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, k))
|
||||
BUG ();
|
||||
log_debug ("ephemeral scalar MPI #0: %s\n", buffer);
|
||||
gcry_free (buffer);
|
||||
}
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
/* Generate an ephemeral key for the public ECDH key in PKEY. On
|
||||
success the generated key is stored at R_K; on failure NULL is
|
||||
stored at R_K and an error code returned. */
|
||||
gpg_error_t
|
||||
pk_ecdh_generate_ephemeral_key (gcry_mpi_t *pkey, gcry_mpi_t *r_k)
|
||||
{
|
||||
unsigned int nbits;
|
||||
gcry_mpi_t k;
|
||||
|
||||
*r_k = NULL;
|
||||
|
||||
nbits = pubkey_nbits (PUBKEY_ALGO_ECDH, pkey);
|
||||
if (!nbits)
|
||||
return gpg_error (GPG_ERR_TOO_SHORT);
|
||||
k = gen_k (nbits);
|
||||
if (!k)
|
||||
BUG ();
|
||||
|
||||
*r_k = k;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 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 shared, gcry_mpi_t * skey)
|
||||
{
|
||||
if (!data)
|
||||
return gpg_error (GPG_ERR_BAD_MPI);
|
||||
return pk_ecdh_encrypt_with_shared_point (0 /*=decryption*/, shared,
|
||||
sk_fp, data/*encr data as an MPI*/,
|
||||
skey, result);
|
||||
}
|
@ -904,9 +904,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, pk, pk->pkey);
|
||||
gcry_mpi_release (frame);
|
||||
if (rc)
|
||||
log_error ("pubkey_encrypt failed: %s\n", gpg_strerror (rc) );
|
||||
@ -916,7 +916,7 @@ write_pubkey_enc_from_list (PK_LIST pk_list, DEK *dek, iobuf_t out)
|
||||
{
|
||||
char *ustr = get_user_id_string_native (enc->keyid);
|
||||
log_info (_("%s/%s encrypted for: \"%s\"\n"),
|
||||
gcry_pk_algo_name (enc->pubkey_algo),
|
||||
openpgp_pk_algo_name (enc->pubkey_algo),
|
||||
openpgp_cipher_algo_name (dek->algo),
|
||||
ustr );
|
||||
xfree (ustr);
|
||||
|
94
g10/export.c
94
g10/export.c
@ -354,7 +354,7 @@ canon_pubkey_algo (int algo)
|
||||
|
||||
|
||||
/* Use the key transfer format given in S_PGP to create the secinfo
|
||||
structure in PK and chnage the parameter array in PK to include the
|
||||
structure in PK and change the parameter array in PK to include the
|
||||
secret parameters. */
|
||||
static gpg_error_t
|
||||
transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
||||
@ -460,6 +460,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
||||
|| gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey)
|
||||
|| !npkey || npkey >= nskey || nskey > PUBKEY_MAX_NSKEY)
|
||||
goto bad_seckey;
|
||||
pubkey_algo = map_pk_gcry_to_openpgp (pubkey_algo);
|
||||
|
||||
gcry_sexp_release (list);
|
||||
list = gcry_sexp_find_token (top_list, "skey", 0);
|
||||
@ -557,6 +558,77 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* We need to change the received parameters for ECC algorithms.
|
||||
The transfer format has all parameters but OpenPGP defines that
|
||||
only the OID of the curve is to be used. */
|
||||
if (pubkey_algo == PUBKEY_ALGO_ECDSA || pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
gcry_sexp_t s_pubkey;
|
||||
const char *curvename, *curveoidstr;
|
||||
gcry_mpi_t mpi;
|
||||
|
||||
/* We build an S-expression with the public key parameters and
|
||||
ask Libgcrypt to return the matching curve name. */
|
||||
if (npkey != 6 || !skey[0] || !skey[1] || !skey[2]
|
||||
|| !skey[3] || !skey[4] || !skey[5]
|
||||
|| !skey[6] || skey[7])
|
||||
{
|
||||
err = gpg_error (GPG_ERR_INTERNAL);
|
||||
goto leave;
|
||||
}
|
||||
err = gcry_sexp_build (&s_pubkey, NULL,
|
||||
"(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)))",
|
||||
skey[0], skey[1], skey[2], skey[3], skey[4]);
|
||||
if (err)
|
||||
goto leave;
|
||||
#ifdef HAVE_GCRY_PK_GET_CURVE
|
||||
curvename = gcry_pk_get_curve (s_pubkey, 0, NULL);
|
||||
#else
|
||||
curvename = "?";
|
||||
#endif
|
||||
gcry_sexp_release (s_pubkey);
|
||||
curveoidstr = gpg_curve_to_oid (curvename, NULL);
|
||||
if (!curveoidstr)
|
||||
{
|
||||
log_error ("no OID known for curve `%s'\n", curvename);
|
||||
err = gpg_error (GPG_ERR_UNKNOWN_NAME);
|
||||
goto leave;
|
||||
}
|
||||
err = openpgp_oid_from_str (curveoidstr, &mpi);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Now replace the curve parameters by the OID and shift the
|
||||
rest of the parameters. */
|
||||
gcry_mpi_release (skey[0]);
|
||||
skey[0] = mpi;
|
||||
for (idx=1; idx <= 4; idx++)
|
||||
gcry_mpi_release (skey[idx]);
|
||||
skey[1] = skey[5];
|
||||
skey[2] = skey[6];
|
||||
for (idx=3; idx <= 6; idx++)
|
||||
skey[idx] = NULL;
|
||||
|
||||
/* Fixup the NPKEY and NSKEY to match OpenPGP reality. */
|
||||
npkey = 2;
|
||||
nskey = 3;
|
||||
|
||||
/* for (idx=0; skey[idx]; idx++) */
|
||||
/* { */
|
||||
/* log_info ("YYY skey[%d]:", idx); */
|
||||
/* if (gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE)) */
|
||||
/* { */
|
||||
/* void *p; */
|
||||
/* unsigned int nbits; */
|
||||
/* p = gcry_mpi_get_opaque (skey[idx], &nbits); */
|
||||
/* log_printhex (NULL, p, (nbits+7)/8); */
|
||||
/* } */
|
||||
/* else */
|
||||
/* gcry_mpi_dump (skey[idx]); */
|
||||
/* log_printf ("\n"); */
|
||||
/* } */
|
||||
}
|
||||
|
||||
/* Do some sanity checks. */
|
||||
if (s2k_count <= 1024)
|
||||
{
|
||||
@ -577,10 +649,16 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Check that the public key parameters match. */
|
||||
/* Check that the public key parameters match. Since Libgcrypt 1.5
|
||||
and the gcry_pk_get_curve function, gcry_mpi_cmp handles opaque
|
||||
MPI correctly and thus we don't need to to do the extra
|
||||
opaqueness checks. */
|
||||
for (idx=0; idx < npkey; idx++)
|
||||
if (gcry_mpi_get_flag (pk->pkey[idx], GCRYMPI_FLAG_OPAQUE)
|
||||
if (0
|
||||
#ifndef HAVE_GCRY_PK_GET_CURVE
|
||||
gcry_mpi_get_flag (pk->pkey[idx], GCRYMPI_FLAG_OPAQUE)
|
||||
|| gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE)
|
||||
#endif
|
||||
|| gcry_mpi_cmp (pk->pkey[idx], skey[idx]))
|
||||
{
|
||||
err = gpg_error (GPG_ERR_BAD_PUBKEY);
|
||||
@ -1215,6 +1293,16 @@ 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);
|
||||
}
|
||||
|
@ -858,7 +858,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;
|
||||
@ -1959,6 +1959,9 @@ main (int argc, char **argv)
|
||||
NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
|
||||
}
|
||||
|
||||
/* Use our own logging handler for Libcgrypt. */
|
||||
setup_libgcrypt_logging ();
|
||||
|
||||
/* Put random number into secure memory */
|
||||
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
|
||||
|
||||
|
170
g10/import.c
170
g10/import.c
@ -1,6 +1,6 @@
|
||||
/* import.c - import a key into our key storage.
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
||||
* 2007, 2010 Free Software Foundation, Inc.
|
||||
* 2007, 2010, 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -1107,6 +1107,37 @@ import_one (ctrl_t ctrl,
|
||||
}
|
||||
|
||||
|
||||
/* Extract one MPI value from the S-expression PKEY which is expected
|
||||
to hold a "public-key". Returns NULL on error. */
|
||||
static gcry_mpi_t
|
||||
one_mpi_from_pkey (gcry_sexp_t pkey, const char *name, size_t namelen)
|
||||
{
|
||||
gcry_sexp_t list, l2;
|
||||
gcry_mpi_t a;
|
||||
|
||||
list = gcry_sexp_find_token (pkey, "public-key", 0);
|
||||
if (!list)
|
||||
return NULL;
|
||||
l2 = gcry_sexp_cadr (list);
|
||||
gcry_sexp_release (list);
|
||||
list = l2;
|
||||
if (!list)
|
||||
return NULL;
|
||||
|
||||
l2 = gcry_sexp_find_token (list, name, namelen);
|
||||
if (!l2)
|
||||
{
|
||||
gcry_sexp_release (list);
|
||||
return NULL;
|
||||
}
|
||||
a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
|
||||
gcry_sexp_release (l2);
|
||||
gcry_sexp_release (list);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
/* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent. The
|
||||
function prints diagnostics and returns an error code. */
|
||||
static gpg_error_t
|
||||
@ -1133,6 +1164,7 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
|
||||
unsigned char *wrappedkey = NULL;
|
||||
size_t wrappedkeylen;
|
||||
char *cache_nonce = NULL;
|
||||
gcry_mpi_t ecc_params[5] = {NULL, NULL, NULL, NULL, NULL};
|
||||
|
||||
/* Get the current KEK. */
|
||||
err = agent_keywrap_key (ctrl, 0, &kek, &keklen);
|
||||
@ -1148,7 +1180,8 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
|
||||
if (!err)
|
||||
err = gcry_cipher_setkey (cipherhd, kek, keklen);
|
||||
if (err)
|
||||
goto leave; xfree (kek);
|
||||
goto leave;
|
||||
xfree (kek);
|
||||
kek = NULL;
|
||||
|
||||
main_pk = NULL;
|
||||
@ -1161,6 +1194,20 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
|
||||
if (!main_pk)
|
||||
main_pk = pk;
|
||||
|
||||
/* Make sure the keyids are available. */
|
||||
keyid_from_pk (pk, NULL);
|
||||
if (node->pkt->pkttype == PKT_SECRET_KEY)
|
||||
{
|
||||
pk->main_keyid[0] = pk->keyid[0];
|
||||
pk->main_keyid[1] = pk->keyid[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
pk->main_keyid[0] = main_pk->keyid[0];
|
||||
pk->main_keyid[1] = main_pk->keyid[1];
|
||||
}
|
||||
|
||||
|
||||
ski = pk->seckey_info;
|
||||
if (!ski)
|
||||
BUG ();
|
||||
@ -1191,34 +1238,109 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
|
||||
|
||||
init_membuf (&mbuf, 50);
|
||||
put_membuf_str (&mbuf, "(skey");
|
||||
for (i=j=0; i < nskey; i++)
|
||||
if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
if (!pk->pkey[i])
|
||||
; /* Protected keys only have NPKEY+1 elements. */
|
||||
else if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
put_membuf_str (&mbuf, " e %b");
|
||||
format_args_buf_ptr[i] = gcry_mpi_get_opaque (pk->pkey[i], &n);
|
||||
format_args_buf_int[i] = (n+7)/8;
|
||||
format_args[j++] = format_args_buf_int + i;
|
||||
format_args[j++] = format_args_buf_ptr + i;
|
||||
}
|
||||
/* We need special treatment for ECC algorithms. OpenPGP
|
||||
stores only the curve name but the agent expects a full
|
||||
key. This is so that we can keep all curve name
|
||||
validation code out of gpg-agent. */
|
||||
#if PUBKEY_MAX_NSKEY < 7
|
||||
#error PUBKEY_MAX_NSKEY too low for ECC
|
||||
#endif
|
||||
char *curve = openpgp_oid_to_str (pk->pkey[0]);
|
||||
if (!curve)
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
put_membuf_str (&mbuf, " _ %m");
|
||||
format_args[j++] = pk->pkey + i;
|
||||
#ifdef HAVE_GCRY_PK_GET_CURVE /* Also ensures availability of get_param. */
|
||||
gcry_sexp_t cparam = gcry_pk_get_param (GCRY_PK_ECDSA, curve);
|
||||
#else
|
||||
gcry_sexp_t cparam = NULL;
|
||||
#endif
|
||||
xfree (curve);
|
||||
if (!cparam)
|
||||
err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
|
||||
else
|
||||
{
|
||||
const char *s;
|
||||
|
||||
/* Append the curve parameters P, A, B, G and N. */
|
||||
for (i=j=0; !err && *(s = "pabgn"+i); i++)
|
||||
{
|
||||
ecc_params[i] = one_mpi_from_pkey (cparam, s, 1);
|
||||
if (!ecc_params[i])
|
||||
err = gpg_error (GPG_ERR_INV_CURVE);
|
||||
else
|
||||
{
|
||||
put_membuf_str (&mbuf, " _ %m");
|
||||
format_args[j++] = ecc_params+i;
|
||||
}
|
||||
}
|
||||
gcry_sexp_release (cparam);
|
||||
if (!err)
|
||||
{
|
||||
/* Append the public key element Q. */
|
||||
put_membuf_str (&mbuf, " _ %m");
|
||||
format_args[j++] = pk->pkey + 1;
|
||||
|
||||
/* Append the secret key element D. Note that
|
||||
for ECDH we need to skip PKEY[2] because this
|
||||
holds the KEK which is not needed. */
|
||||
i = pk->pubkey_algo == PUBKEY_ALGO_ECDH? 3 : 2;
|
||||
if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
put_membuf_str (&mbuf, " e %b");
|
||||
format_args_buf_ptr[i]
|
||||
= gcry_mpi_get_opaque (pk->pkey[i],&n);
|
||||
format_args_buf_int[i] = (n+7)/8;
|
||||
format_args[j++] = format_args_buf_int + i;
|
||||
format_args[j++] = format_args_buf_ptr + i;
|
||||
}
|
||||
else
|
||||
{
|
||||
put_membuf_str (&mbuf, " _ %m");
|
||||
format_args[j++] = pk->pkey + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Standard case for the old (non-ECC) algorithms. */
|
||||
for (i=j=0; i < nskey; i++)
|
||||
{
|
||||
if (!pk->pkey[i])
|
||||
; /* Protected keys only have NPKEY+1 elements. */
|
||||
else if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
put_membuf_str (&mbuf, " e %b");
|
||||
format_args_buf_ptr[i] = gcry_mpi_get_opaque (pk->pkey[i],&n);
|
||||
format_args_buf_int[i] = (n+7)/8;
|
||||
format_args[j++] = format_args_buf_int + i;
|
||||
format_args[j++] = format_args_buf_ptr + i;
|
||||
}
|
||||
else
|
||||
{
|
||||
put_membuf_str (&mbuf, " _ %m");
|
||||
format_args[j++] = pk->pkey + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
put_membuf_str (&mbuf, ")\n");
|
||||
put_membuf (&mbuf, "", 1);
|
||||
{
|
||||
char *format = get_membuf (&mbuf, NULL);
|
||||
if (!format)
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
err = gcry_sexp_build_array (&skey, NULL, format, format_args);
|
||||
xfree (format);
|
||||
}
|
||||
if (err)
|
||||
xfree (get_membuf (&mbuf, NULL));
|
||||
else
|
||||
{
|
||||
char *format = get_membuf (&mbuf, NULL);
|
||||
if (!format)
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
err = gcry_sexp_build_array (&skey, NULL, format, format_args);
|
||||
xfree (format);
|
||||
}
|
||||
if (err)
|
||||
{
|
||||
log_error ("error building skey array: %s\n", gpg_strerror (err));
|
||||
@ -1328,6 +1450,8 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
|
||||
}
|
||||
|
||||
leave:
|
||||
for (i=0; i < DIM (ecc_params); i++)
|
||||
gcry_mpi_release (ecc_params[i]);
|
||||
xfree (cache_nonce);
|
||||
xfree (wrappedkey);
|
||||
xfree (transferkey);
|
||||
|
230
g10/keygen.c
230
g10/keygen.c
@ -1,6 +1,6 @@
|
||||
/* keygen.c - generate a key pair
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
|
||||
* 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
* 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -42,6 +42,7 @@
|
||||
#include "i18n.h"
|
||||
#include "keyserver-internal.h"
|
||||
#include "call-agent.h"
|
||||
#include "pkglue.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 +50,11 @@
|
||||
#define DEFAULT_STD_ALGO GCRY_PK_RSA
|
||||
#define DEFAULT_STD_KEYSIZE 2048
|
||||
|
||||
/* Flag bits used during key generation. */
|
||||
#define KEYGEN_FLAG_NO_PROTECTION 1
|
||||
#define KEYGEN_FLAG_TRANSIENT_KEY 2
|
||||
|
||||
|
||||
/* Maximum number of supported algorithm preferences. */
|
||||
#define MAX_PREFS 30
|
||||
|
||||
enum para_name {
|
||||
@ -1078,8 +1080,130 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Map the Libgcrypt ECC curve NAME to an OID. If R_NBITS is not NULL
|
||||
store the bit size of the curve there. Returns NULL for unknown
|
||||
curve names. */
|
||||
const char *
|
||||
gpg_curve_to_oid (const char *name, unsigned int *r_nbits)
|
||||
{
|
||||
unsigned int nbits = 0;
|
||||
const char *oidstr;
|
||||
|
||||
if (!name)
|
||||
oidstr = NULL;
|
||||
else if (!strcmp (name, "NIST P-256"))
|
||||
{
|
||||
oidstr = "1.2.840.10045.3.1.7";
|
||||
nbits = 256;
|
||||
}
|
||||
else if (!strcmp (name, "NIST P-384"))
|
||||
{
|
||||
oidstr = "1.3.132.0.34";
|
||||
nbits = 384;
|
||||
}
|
||||
else if (!strcmp (name, "NIST P-521"))
|
||||
{
|
||||
oidstr = "1.3.132.0.35";
|
||||
nbits = 521;
|
||||
}
|
||||
else
|
||||
oidstr = NULL;
|
||||
|
||||
if (r_nbits)
|
||||
*r_nbits = nbits;
|
||||
return oidstr;
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gcry_sexp_t list, l2;
|
||||
char *curve;
|
||||
int i;
|
||||
const char *oidstr;
|
||||
unsigned int nbits;
|
||||
|
||||
array[0] = NULL;
|
||||
array[1] = NULL;
|
||||
array[2] = NULL;
|
||||
|
||||
list = gcry_sexp_find_token (sexp, "public-key", 0);
|
||||
if (!list)
|
||||
return gpg_error (GPG_ERR_INV_OBJ);
|
||||
l2 = gcry_sexp_cadr (list);
|
||||
gcry_sexp_release (list);
|
||||
list = l2;
|
||||
if (!list)
|
||||
return gpg_error (GPG_ERR_NO_OBJ);
|
||||
|
||||
l2 = gcry_sexp_find_token (list, "curve", 0);
|
||||
if (!l2)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NO_OBJ);
|
||||
goto leave;
|
||||
}
|
||||
curve = gcry_sexp_nth_string (l2, 1);
|
||||
if (!curve)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NO_OBJ);
|
||||
goto leave;
|
||||
}
|
||||
gcry_sexp_release (l2);
|
||||
oidstr = gpg_curve_to_oid (curve, &nbits);
|
||||
if (!oidstr)
|
||||
{
|
||||
/* That can't happen because we used one of the curves
|
||||
gpg_curve_to_oid knows about. */
|
||||
err = gpg_error (GPG_ERR_INV_OBJ);
|
||||
goto leave;
|
||||
}
|
||||
err = openpgp_oid_from_str (oidstr, &array[0]);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
l2 = gcry_sexp_find_token (list, "q", 0);
|
||||
if (!l2)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NO_OBJ);
|
||||
goto leave;
|
||||
}
|
||||
array[1] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
|
||||
gcry_sexp_release (l2);
|
||||
if (!array[1])
|
||||
{
|
||||
err = gpg_error (GPG_ERR_INV_OBJ);
|
||||
goto leave;
|
||||
}
|
||||
gcry_sexp_release (list);
|
||||
|
||||
if (algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
array[2] = pk_ecdh_default_params (nbits);
|
||||
if (!array[2])
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
if (err)
|
||||
{
|
||||
for (i=0; i < 3; i++)
|
||||
{
|
||||
gcry_mpi_release (array[i]);
|
||||
array[i] = NULL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Extract key parameters from SEXP and store them in ARRAY. ELEMS is
|
||||
a string where each character denotes a parameter name. TOPNAME is
|
||||
the name of the top element above the elements. */
|
||||
static int
|
||||
key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
|
||||
const char *topname, const char *elems)
|
||||
@ -1130,7 +1254,6 @@ 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,
|
||||
@ -1164,7 +1287,10 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
|
||||
pk->expiredate = pk->timestamp + expireval;
|
||||
pk->pubkey_algo = algo;
|
||||
|
||||
err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
|
||||
if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
|
||||
err = ecckey_from_sexp (pk->pkey, s_key, algo);
|
||||
else
|
||||
err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
|
||||
if (err)
|
||||
{
|
||||
log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) );
|
||||
@ -1327,6 +1453,50 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Generate an ECC key
|
||||
*/
|
||||
static gpg_error_t
|
||||
gen_ecc (int algo, unsigned int nbits, kbnode_t pub_root,
|
||||
u32 timestamp, u32 expireval, int is_subkey,
|
||||
int keygen_flags, char **cache_nonce_addr)
|
||||
{
|
||||
gpg_error_t err;
|
||||
const char *curve;
|
||||
char *keyparms;
|
||||
|
||||
assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH);
|
||||
|
||||
/* For now we may only use one of the 3 NIST curves. See also
|
||||
gpg_curve_to_oid. */
|
||||
if (nbits <= 256)
|
||||
curve = "NIST P-256";
|
||||
else if (nbits <= 384)
|
||||
curve = "NIST P-384";
|
||||
else
|
||||
curve = "NIST P-521";
|
||||
|
||||
keyparms = xtryasprintf ("(genkey(%s(curve %zu:%s)%s))",
|
||||
algo == PUBKEY_ALGO_ECDSA ? "ecdsa" : "ecdh",
|
||||
strlen (curve), curve,
|
||||
((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
|
||||
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
|
||||
"(transient-key)" : "" );
|
||||
if (!keyparms)
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
err = common_gen (keyparms, algo, "",
|
||||
pub_root, timestamp, expireval, is_subkey,
|
||||
keygen_flags, cache_nonce_addr);
|
||||
xfree (keyparms);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Generate an RSA key.
|
||||
*/
|
||||
@ -1557,6 +1727,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 +1785,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,15 +1835,22 @@ 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(;;)
|
||||
for (;;)
|
||||
{
|
||||
char *prompt, *answer;
|
||||
|
||||
@ -1682,25 +1867,39 @@ 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;
|
||||
}
|
||||
|
||||
tty_printf(_("Requested keysize is %u bits\n"), nbits );
|
||||
tty_printf (_("Requested keysize is %u bits\n"), nbits);
|
||||
|
||||
leave:
|
||||
if( algo == PUBKEY_ALGO_DSA && (nbits % 64) )
|
||||
if (algo == PUBKEY_ALGO_DSA && (nbits % 64))
|
||||
{
|
||||
nbits = ((nbits + 63) / 64) * 64;
|
||||
if (!autocomp)
|
||||
tty_printf(_("rounded up to %u bits\n"), nbits );
|
||||
tty_printf (_("rounded up to %u bits\n"), nbits);
|
||||
}
|
||||
else if( (nbits % 32) )
|
||||
else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
|
||||
{
|
||||
if (nbits != 256 && nbits != 384 && nbits != 521)
|
||||
{
|
||||
if (nbits < 256)
|
||||
nbits = 256;
|
||||
else if (nbits < 384)
|
||||
nbits = 384;
|
||||
else
|
||||
nbits = 521;
|
||||
if (!autocomp)
|
||||
tty_printf (_("rounded to %u bits\n"), nbits);
|
||||
}
|
||||
}
|
||||
else if ((nbits % 32))
|
||||
{
|
||||
nbits = ((nbits + 31) / 32) * 32;
|
||||
if (!autocomp)
|
||||
tty_printf(_("rounded up to %u bits\n"), nbits );
|
||||
tty_printf (_("rounded up to %u bits\n"), nbits );
|
||||
}
|
||||
|
||||
return nbits;
|
||||
@ -2185,6 +2384,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);
|
||||
@ -2271,7 +2473,7 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
|
||||
|| !strcmp (r->u.value, "ELG"))
|
||||
i = GCRY_PK_ELG_E;
|
||||
else
|
||||
i = gcry_pk_map_name (r->u.value);
|
||||
i = map_pk_gcry_to_openpgp (gcry_pk_map_name (r->u.value));
|
||||
|
||||
if (i == PUBKEY_ALGO_RSA_E || i == PUBKEY_ALGO_RSA_S)
|
||||
i = 0; /* we don't want to allow generation of these algorithms */
|
||||
|
59
g10/keyid.c
59
g10/keyid.c
@ -54,9 +54,11 @@ pubkey_letter( int algo )
|
||||
case PUBKEY_ALGO_RSA: return 'R' ;
|
||||
case PUBKEY_ALGO_RSA_E: return 'r' ;
|
||||
case PUBKEY_ALGO_RSA_S: return 's' ;
|
||||
case PUBKEY_ALGO_ELGAMAL_E: return 'g';
|
||||
case PUBKEY_ALGO_ELGAMAL_E: return 'g' ;
|
||||
case PUBKEY_ALGO_ELGAMAL: return 'G' ;
|
||||
case PUBKEY_ALGO_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 '?';
|
||||
}
|
||||
}
|
||||
@ -79,6 +81,11 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
|
||||
if(pk->version<4)
|
||||
n+=2;
|
||||
|
||||
/* FIXME: We can avoid the extra malloc by calling only the first
|
||||
mpi_print here which computes the required length and calling the
|
||||
real mpi_print only at the end. The speed advantage would only be
|
||||
for ECC (opaque MPIs) or if we could implement an mpi_print
|
||||
variant with a callback handler to do the hashing. */
|
||||
if (npkey==0 && pk->pkey[0]
|
||||
&& gcry_mpi_get_flag (pk->pkey[0], GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
@ -88,16 +95,31 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
|
||||
}
|
||||
else
|
||||
{
|
||||
for(i=0; i < npkey; i++ )
|
||||
for (i=0; i < npkey; i++ )
|
||||
{
|
||||
if (gcry_mpi_print (GCRYMPI_FMT_PGP, 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]))
|
||||
BUG ();
|
||||
nn[i] = nbytes;
|
||||
n += nn[i];
|
||||
if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
size_t nbits;
|
||||
const void *p;
|
||||
|
||||
p = gcry_mpi_get_opaque (pk->pkey[i], &nbits);
|
||||
pp[i] = xmalloc ((nbits+7)/8);
|
||||
memcpy (pp[i], p, (nbits+7)/8);
|
||||
nn[i] = (nbits+7)/8;
|
||||
n += nn[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gcry_mpi_print (GCRYMPI_FMT_PGP, 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]))
|
||||
BUG ();
|
||||
nn[i] = nbytes;
|
||||
n += nn[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -712,6 +734,22 @@ 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:
|
||||
{
|
||||
char *curve = openpgp_oid_to_str (pk->pkey[0]);
|
||||
if (!curve)
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
err = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(ecc(curve%s)(q%m)))",
|
||||
curve, pk->pkey[1]);
|
||||
xfree (curve);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
break;
|
||||
@ -760,4 +798,3 @@ hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip)
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
24
g10/main.h
24
g10/main.h
@ -87,17 +87,22 @@ u16 checksum_mpi( gcry_mpi_t a );
|
||||
u32 buffer_to_u32( const byte *buffer );
|
||||
const byte *get_session_marker( size_t *rlen );
|
||||
int map_cipher_openpgp_to_gcry (int algo);
|
||||
#define openpgp_cipher_open(_a,_b,_c,_d) gcry_cipher_open((_a),map_cipher_openpgp_to_gcry((_b)),(_c),(_d))
|
||||
#define openpgp_cipher_get_algo_keylen(_a) gcry_cipher_get_algo_keylen(map_cipher_openpgp_to_gcry((_a)))
|
||||
#define openpgp_cipher_get_algo_blklen(_a) gcry_cipher_get_algo_blklen(map_cipher_openpgp_to_gcry((_a)))
|
||||
#define openpgp_cipher_open(_a,_b,_c,_d) \
|
||||
gcry_cipher_open((_a),map_cipher_openpgp_to_gcry((_b)),(_c),(_d))
|
||||
#define openpgp_cipher_get_algo_keylen(_a) \
|
||||
gcry_cipher_get_algo_keylen(map_cipher_openpgp_to_gcry((_a)))
|
||||
#define openpgp_cipher_get_algo_blklen(_a) \
|
||||
gcry_cipher_get_algo_blklen(map_cipher_openpgp_to_gcry((_a)))
|
||||
int openpgp_cipher_blocklen (int algo);
|
||||
int openpgp_cipher_test_algo( int algo );
|
||||
const char *openpgp_cipher_algo_name (int algo);
|
||||
int map_pk_openpgp_to_gcry (int algo);
|
||||
int map_pk_gcry_to_openpgp (enum gcry_pk_algos 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
|
||||
@ -150,13 +155,16 @@ int is_valid_mailbox (const char *name);
|
||||
const char *get_libexecdir (void);
|
||||
int path_access(const char *file,int mode);
|
||||
|
||||
/* Temporary helpers. */
|
||||
int pubkey_get_npkey( int algo );
|
||||
int pubkey_get_nskey( int algo );
|
||||
int pubkey_get_nsig( int algo );
|
||||
int pubkey_get_nenc( int algo );
|
||||
|
||||
/* Temporary helpers. */
|
||||
unsigned int pubkey_nbits( int algo, gcry_mpi_t *pkey );
|
||||
int mpi_print (estream_t stream, gcry_mpi_t a, int mode);
|
||||
unsigned int ecdsa_qbits_from_Q (unsigned int qbits);
|
||||
|
||||
|
||||
/*-- status.c --*/
|
||||
void set_status_fd ( int fd );
|
||||
@ -228,6 +236,7 @@ void keyedit_passwd (ctrl_t ctrl, const char *username);
|
||||
void show_basic_key_info (KBNODE keyblock);
|
||||
|
||||
/*-- keygen.c --*/
|
||||
const char *gpg_curve_to_oid (const char *name, unsigned int *r_nbits);
|
||||
u32 parse_expire_string(const char *string);
|
||||
u32 ask_expire_interval(int object,const char *def_expire);
|
||||
u32 ask_expiredate(void);
|
||||
@ -251,6 +260,7 @@ gpg_error_t generate_card_subkeypair (kbnode_t pub_keyblock,
|
||||
int save_unprotected_key_to_card (PKT_public_key *sk, int keyno);
|
||||
#endif
|
||||
|
||||
|
||||
/*-- openfile.c --*/
|
||||
int overwrite_filep( const char *fname );
|
||||
char *make_outfile_name( const char *iname );
|
||||
@ -261,7 +271,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 );
|
||||
|
||||
@ -294,7 +304,7 @@ gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec,
|
||||
int export_seckeys (ctrl_t ctrl, strlist_t users);
|
||||
int export_secsubkeys (ctrl_t ctrl, strlist_t users);
|
||||
|
||||
/* dearmor.c --*/
|
||||
/*-- dearmor.c --*/
|
||||
int dearmor_file( const char *fname );
|
||||
int enarmor_file( const char *fname );
|
||||
|
||||
|
@ -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
@ -1,6 +1,6 @@
|
||||
/* misc.c - miscellaneous functions
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
* 2008, 2009 Free Software Foundation, Inc.
|
||||
* 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -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,32 @@ map_cipher_gcry_to_openpgp (int algo)
|
||||
}
|
||||
}
|
||||
|
||||
/* Map OpenPGP public key algorithm numbers to those used by
|
||||
Libgcrypt. */
|
||||
int
|
||||
map_pk_openpgp_to_gcry (int algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case PUBKEY_ALGO_ECDSA: return GCRY_PK_ECDSA;
|
||||
case PUBKEY_ALGO_ECDH: return GCRY_PK_ECDH;
|
||||
default: return algo;
|
||||
}
|
||||
}
|
||||
|
||||
/* Map Gcrypt public key algorithm numbers to those used by
|
||||
OpenPGP. */
|
||||
int
|
||||
map_pk_gcry_to_openpgp (enum gcry_pk_algos algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA;
|
||||
case GCRY_PK_ECDH: return PUBKEY_ALGO_ECDH;
|
||||
default: return algo < 110 ? algo : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return the block length of an OpenPGP cipher algorithm. */
|
||||
int
|
||||
@ -424,7 +451,8 @@ openpgp_pk_test_algo( int algo )
|
||||
|
||||
if (algo < 0 || algo > 110)
|
||||
return gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
return gcry_pk_test_algo (algo);
|
||||
|
||||
return gcry_pk_test_algo (map_pk_openpgp_to_gcry (algo));
|
||||
}
|
||||
|
||||
int
|
||||
@ -442,7 +470,8 @@ 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);
|
||||
return gcry_pk_algo_info (map_pk_openpgp_to_gcry (algo),
|
||||
GCRYCTL_TEST_ALGO, NULL, &use_buf);
|
||||
}
|
||||
|
||||
int
|
||||
@ -457,6 +486,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 +502,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;
|
||||
}
|
||||
@ -484,19 +516,7 @@ openpgp_pk_algo_usage ( int algo )
|
||||
const char *
|
||||
openpgp_pk_algo_name (int algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case PUBKEY_ALGO_RSA:
|
||||
case PUBKEY_ALGO_RSA_E:
|
||||
case PUBKEY_ALGO_RSA_S: return "rsa";
|
||||
|
||||
case PUBKEY_ALGO_ELGAMAL:
|
||||
case PUBKEY_ALGO_ELGAMAL_E: return "elg";
|
||||
|
||||
case PUBKEY_ALGO_DSA: return "dsa";
|
||||
|
||||
default: return "?";
|
||||
}
|
||||
return gcry_pk_algo_name (map_pk_openpgp_to_gcry (algo));
|
||||
}
|
||||
|
||||
|
||||
@ -1340,27 +1360,44 @@ path_access(const char *file,int mode)
|
||||
|
||||
|
||||
|
||||
/* Temporary helper. */
|
||||
/* Return the number of public key parameters as used by OpenPGP. */
|
||||
int
|
||||
pubkey_get_npkey( int algo )
|
||||
pubkey_get_npkey (int algo)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
/* ECC is special. */
|
||||
if (algo == PUBKEY_ALGO_ECDSA)
|
||||
return 2;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
return 3;
|
||||
|
||||
/* All other algorithms match those of Libgcrypt. */
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &n))
|
||||
|
||||
if (gcry_pk_algo_info (algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &n))
|
||||
n = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Temporary helper. */
|
||||
|
||||
/* Return the number of secret key parameters as used by OpenPGP. */
|
||||
int
|
||||
pubkey_get_nskey( int algo )
|
||||
pubkey_get_nskey (int algo)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
/* ECC is special. */
|
||||
if (algo == PUBKEY_ALGO_ECDSA)
|
||||
return 3;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
return 4;
|
||||
|
||||
/* All other algorithms match those of Libgcrypt. */
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
|
||||
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &n ))
|
||||
n = 0;
|
||||
return n;
|
||||
@ -1368,25 +1405,40 @@ pubkey_get_nskey( int algo )
|
||||
|
||||
/* Temporary helper. */
|
||||
int
|
||||
pubkey_get_nsig( int algo )
|
||||
pubkey_get_nsig (int algo)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
/* ECC is special. */
|
||||
if (algo == PUBKEY_ALGO_ECDSA)
|
||||
return 2;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
return 0;
|
||||
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
|
||||
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSIGN, NULL, &n))
|
||||
n = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/* Temporary helper. */
|
||||
int
|
||||
pubkey_get_nenc( int algo )
|
||||
pubkey_get_nenc (int algo)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
/* ECC is special. */
|
||||
if (algo == PUBKEY_ALGO_ECDSA)
|
||||
return 0;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
return 2;
|
||||
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
|
||||
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NENCR, NULL, &n ))
|
||||
n = 0;
|
||||
return n;
|
||||
@ -1400,6 +1452,9 @@ pubkey_nbits( int algo, gcry_mpi_t *key )
|
||||
int rc, nbits;
|
||||
gcry_sexp_t sexp;
|
||||
|
||||
#warning FIXME: We are mixing OpenPGP And CGrypt Ids
|
||||
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 +1470,18 @@ 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 ) {
|
||||
char *curve = openpgp_oid_to_str (key[0]);
|
||||
if (!curve)
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
rc = gcry_sexp_build (&sexp, NULL,
|
||||
"(public-key(ecc(curve%s)(q%m)))",
|
||||
curve, key[1]);
|
||||
xfree (curve);
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
@ -1428,7 +1495,6 @@ pubkey_nbits( int algo, gcry_mpi_t *key )
|
||||
|
||||
|
||||
|
||||
/* FIXME: Use gcry_mpi_print directly. */
|
||||
int
|
||||
mpi_print (estream_t fp, gcry_mpi_t a, int mode)
|
||||
{
|
||||
@ -1442,6 +1508,19 @@ mpi_print (estream_t fp, gcry_mpi_t a, int mode)
|
||||
n1 = gcry_mpi_get_nbits(a);
|
||||
n += es_fprintf (fp, "[%u bits]", n1);
|
||||
}
|
||||
else if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
unsigned int nbits;
|
||||
unsigned char *p = gcry_mpi_get_opaque (a, &nbits);
|
||||
if (!p)
|
||||
n += es_fprintf (fp, "[invalid opaque value]");
|
||||
else
|
||||
{
|
||||
nbits = (nbits + 7)/8;
|
||||
for (; nbits; nbits--, p++)
|
||||
n += es_fprintf (fp, "%02X", *p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char *buffer;
|
||||
@ -1455,3 +1534,21 @@ mpi_print (estream_t fp, gcry_mpi_t a, int mode)
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/* pkey[1] or skey[1] is Q for ECDSA, which is an uncompressed point,
|
||||
i.e. 04 <x> <y> */
|
||||
unsigned int
|
||||
ecdsa_qbits_from_Q (unsigned 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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -444,6 +444,7 @@ PACKET *create_gpg_control ( ctrlpkttype_t type,
|
||||
|
||||
/*-- build-packet.c --*/
|
||||
int build_packet( iobuf_t inp, PACKET *pkt );
|
||||
gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a);
|
||||
u32 calc_packet_length( PACKET *pkt );
|
||||
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
|
||||
const byte *buffer, size_t buflen );
|
||||
|
@ -741,6 +741,61 @@ read_rest (IOBUF inp, size_t pktlen, int partial)
|
||||
}
|
||||
|
||||
|
||||
/* Read a special size+body from INP. On success store an opaque MPI
|
||||
with it at R_DATA. On error return an error code and store NULL at
|
||||
R_DATA. Even in the error case store the number of read bytes at
|
||||
R_NREAD. The caller shall pass the remaining size of the packet in
|
||||
PKTLEN. */
|
||||
static gpg_error_t
|
||||
read_size_body (iobuf_t inp, int pktlen, size_t *r_nread,
|
||||
gcry_mpi_t *r_data)
|
||||
{
|
||||
char buffer[256];
|
||||
char *tmpbuf;
|
||||
int i, c, nbytes;
|
||||
|
||||
*r_nread = 0;
|
||||
*r_data = NULL;
|
||||
|
||||
if (!pktlen)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
c = iobuf_readbyte (inp);
|
||||
if (c < 0)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
pktlen--;
|
||||
++*r_nread;
|
||||
nbytes = c;
|
||||
if (nbytes < 2 || nbytes > 254)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
if (nbytes > pktlen)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
|
||||
buffer[0] = nbytes;
|
||||
|
||||
for (i = 0; i < nbytes; i++)
|
||||
{
|
||||
c = iobuf_get (inp);
|
||||
if (c < 0)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
++*r_nread;
|
||||
buffer[1+i] = c;
|
||||
}
|
||||
|
||||
tmpbuf = xtrymalloc (1 + nbytes);
|
||||
if (!tmpbuf)
|
||||
return gpg_error_from_syserror ();
|
||||
memcpy (tmpbuf, buffer, 1 + nbytes);
|
||||
*r_data = gcry_mpi_set_opaque (NULL, tmpbuf, 8 * (1 + nbytes));
|
||||
if (!*r_data)
|
||||
{
|
||||
xfree (tmpbuf);
|
||||
return gpg_error_from_syserror ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Parse a marker packet. */
|
||||
static int
|
||||
parse_marker (IOBUF inp, int pkttype, unsigned long pktlen)
|
||||
{
|
||||
@ -940,19 +995,29 @@ 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 && i == 1)
|
||||
{
|
||||
rc = read_size_body (inp, pktlen, &n, k->data+i);
|
||||
pktlen -= n;
|
||||
}
|
||||
else
|
||||
{
|
||||
n = pktlen;
|
||||
k->data[i] = mpi_read (inp, &n, 0);
|
||||
pktlen -= n;
|
||||
if (!k->data[i])
|
||||
rc = gpg_error (GPG_ERR_INV_PACKET);
|
||||
}
|
||||
if (rc)
|
||||
goto leave;
|
||||
if (list_mode)
|
||||
{
|
||||
es_fprintf (listfp, "\tdata: ");
|
||||
mpi_print (listfp, k->data[i], mpi_print_mode);
|
||||
es_putc ('\n', listfp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
@ -1913,7 +1978,6 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
unknown_pubkey_warning (algorithm);
|
||||
}
|
||||
|
||||
|
||||
if (!npkey)
|
||||
{
|
||||
/* Unknown algorithm - put data into an opaque MPI. */
|
||||
@ -1925,25 +1989,32 @@ 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 (!pk->pkey[i])
|
||||
err = gpg_error (GPG_ERR_INV_PACKET);
|
||||
}
|
||||
if (err)
|
||||
goto leave;
|
||||
{
|
||||
if ((algorithm == PUBKEY_ALGO_ECDSA
|
||||
|| algorithm == PUBKEY_ALGO_ECDH) && (i==0 || i == 2))
|
||||
{
|
||||
err = read_size_body (inp, pktlen, &n, pk->pkey+i);
|
||||
pktlen -= n;
|
||||
}
|
||||
else
|
||||
{
|
||||
n = pktlen;
|
||||
pk->pkey[i] = mpi_read (inp, &n, 0);
|
||||
pktlen -= n;
|
||||
if (!pk->pkey[i])
|
||||
err = gpg_error (GPG_ERR_INV_PACKET);
|
||||
}
|
||||
if (err)
|
||||
goto leave;
|
||||
if (list_mode)
|
||||
{
|
||||
es_fprintf (listfp, "\tpkey[%d]: ", i);
|
||||
mpi_print (listfp, pk->pkey[i], mpi_print_mode);
|
||||
es_putc ('\n', listfp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (list_mode)
|
||||
keyid_from_pk (pk, keyid);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
217
g10/pkglue.c
217
g10/pkglue.c
@ -1,5 +1,5 @@
|
||||
/* pkglue.c - public key operations glue code
|
||||
* Copyright (C) 2000, 2003 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2000, 2003, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -27,9 +27,12 @@
|
||||
#include "gpg.h"
|
||||
#include "util.h"
|
||||
#include "pkglue.h"
|
||||
#include "main.h"
|
||||
#include "options.h"
|
||||
|
||||
|
||||
static gcry_mpi_t
|
||||
/* FIXME: Better chnage the fucntion name because mpi_ is used by
|
||||
gcrypt macros. */
|
||||
gcry_mpi_t
|
||||
mpi_from_sexp (gcry_sexp_t sexp, const char * item)
|
||||
{
|
||||
gcry_sexp_t list;
|
||||
@ -50,42 +53,56 @@ mpi_from_sexp (gcry_sexp_t sexp, const char * item)
|
||||
* change the internal design to directly fit to libgcrypt.
|
||||
*/
|
||||
int
|
||||
pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
|
||||
pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey)
|
||||
{
|
||||
gcry_sexp_t s_sig, s_hash, s_pkey;
|
||||
int rc;
|
||||
const int pkalgo = map_pk_openpgp_to_gcry (algo);
|
||||
|
||||
/* make a sexp from pkey */
|
||||
if (algo == GCRY_PK_DSA)
|
||||
/* Make a sexp from pkey. */
|
||||
if (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 (pkalgo == GCRY_PK_ELG || 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 (pkalgo == GCRY_PK_RSA || 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 (pkalgo == GCRY_PK_ECDSA) /* Same as GCRY_PK_ECDH */
|
||||
{
|
||||
char *curve = openpgp_oid_to_str (pkey[0]);
|
||||
if (!curve)
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
rc = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(ecdsa(curve %s)(q%m)))",
|
||||
curve, pkey[1]);
|
||||
xfree (curve);
|
||||
}
|
||||
}
|
||||
else
|
||||
return GPG_ERR_PUBKEY_ALGO;
|
||||
|
||||
if (rc)
|
||||
BUG (); /* gcry_sexp_build should never fail. */
|
||||
|
||||
/* put hash into a S-Exp s_hash */
|
||||
/* Put hash into a S-Exp s_hash. */
|
||||
if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
|
||||
BUG (); /* gcry_sexp_build should never fail. */
|
||||
|
||||
/* Put data into a S-Exp s_sig. */
|
||||
s_sig = NULL;
|
||||
if (algo == GCRY_PK_DSA)
|
||||
if (pkalgo == GCRY_PK_DSA)
|
||||
{
|
||||
if (!data[0] || !data[1])
|
||||
rc = gpg_error (GPG_ERR_BAD_MPI);
|
||||
@ -93,7 +110,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 (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 (pkalgo == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E)
|
||||
{
|
||||
if (!data[0] || !data[1])
|
||||
rc = gpg_error (GPG_ERR_BAD_MPI);
|
||||
@ -101,7 +126,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 (pkalgo == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_S)
|
||||
{
|
||||
if (!data[0])
|
||||
rc = gpg_error (GPG_ERR_BAD_MPI);
|
||||
@ -126,45 +151,111 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
|
||||
/****************
|
||||
* Emulate our old PK interface here - sometime in the future we might
|
||||
* change the internal design to directly fit to libgcrypt.
|
||||
* PK is only required to compute the fingerprint for ECDH.
|
||||
*/
|
||||
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,
|
||||
PKT_public_key *pk, gcry_mpi_t *pkey)
|
||||
{
|
||||
gcry_sexp_t s_ciph, s_data, s_pkey;
|
||||
int rc;
|
||||
|
||||
/* make a sexp from pkey */
|
||||
/* Make a sexp from pkey. */
|
||||
if (algo == GCRY_PK_ELG || algo == 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]);
|
||||
/* Put DATA into a simplified S-expression. */
|
||||
if (rc || gcry_sexp_build (&s_data, NULL, "%m", data))
|
||||
BUG ();
|
||||
|
||||
}
|
||||
else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_E)
|
||||
{
|
||||
rc = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(rsa(n%m)(e%m)))",
|
||||
pkey[0], pkey[1]);
|
||||
/* Put DATA into a simplified S-expression. */
|
||||
if (rc || gcry_sexp_build (&s_data, NULL, "%m", data))
|
||||
BUG ();
|
||||
}
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
gcry_mpi_t k;
|
||||
char *curve;
|
||||
|
||||
rc = pk_ecdh_generate_ephemeral_key (pkey, &k);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
curve = openpgp_oid_to_str (pkey[0]);
|
||||
if (!curve)
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
/* Now use the ephemeral secret to compute the shared point. */
|
||||
rc = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(ecdh(curve%s)(q%m)))",
|
||||
curve, pkey[1]);
|
||||
xfree (curve);
|
||||
/* FIXME: Take care of RC. */
|
||||
/* Put K into a simplified S-expression. */
|
||||
if (rc || gcry_sexp_build (&s_data, NULL, "%m", k))
|
||||
BUG ();
|
||||
}
|
||||
}
|
||||
else
|
||||
return GPG_ERR_PUBKEY_ALGO;
|
||||
return gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
|
||||
if (rc)
|
||||
BUG ();
|
||||
|
||||
/* put the data into a simple list */
|
||||
if (gcry_sexp_build (&s_data, NULL, "%m", data))
|
||||
BUG ();
|
||||
|
||||
/* pass it to libgcrypt */
|
||||
/* 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)
|
||||
;
|
||||
else
|
||||
{ /* add better error handling or make gnupg use S-Exp directly */
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
gcry_mpi_t shared, public, result;
|
||||
byte fp[MAX_FINGERPRINT_LEN];
|
||||
size_t fpn;
|
||||
|
||||
/* Get the shared point and the ephemeral public key. */
|
||||
shared = mpi_from_sexp (s_ciph, "s");
|
||||
public = mpi_from_sexp (s_ciph, "e");
|
||||
gcry_sexp_release (s_ciph);
|
||||
s_ciph = NULL;
|
||||
if (DBG_CIPHER)
|
||||
{
|
||||
log_debug ("ECDH ephemeral key:");
|
||||
gcry_mpi_dump (public);
|
||||
log_printf ("\n");
|
||||
}
|
||||
|
||||
result = NULL;
|
||||
fingerprint_from_pk (pk, fp, &fpn);
|
||||
if (fpn != 20)
|
||||
rc = gpg_error (GPG_ERR_INV_LENGTH);
|
||||
else
|
||||
rc = pk_ecdh_encrypt_with_shared_point (1 /*=encrypton*/, shared,
|
||||
fp, data, pkey, &result);
|
||||
gcry_mpi_release (shared);
|
||||
if (!rc)
|
||||
{
|
||||
resarr[0] = public;
|
||||
resarr[1] = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
gcry_mpi_release (public);
|
||||
gcry_mpi_release (result);
|
||||
}
|
||||
}
|
||||
else /* Elgamal or RSA case. */
|
||||
{ /* Fixme: Add better error handling or make gnupg use
|
||||
S-expressions directly. */
|
||||
resarr[0] = mpi_from_sexp (s_ciph, "a");
|
||||
if (algo != GCRY_PK_RSA && algo != GCRY_PK_RSA_E)
|
||||
resarr[1] = mpi_from_sexp (s_ciph, "b");
|
||||
@ -175,72 +266,54 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, gcry_mpi_t * pkey)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Emulate our old PK interface here - sometime in the future we might
|
||||
* change the internal design to directly fit to libgcrypt.
|
||||
*/
|
||||
/* Check whether SKEY is a suitable secret key. */
|
||||
int
|
||||
pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data,
|
||||
gcry_mpi_t * skey)
|
||||
pk_check_secret_key (int algo, gcry_mpi_t *skey)
|
||||
{
|
||||
gcry_sexp_t s_skey, s_data, s_plain;
|
||||
gcry_sexp_t s_skey;
|
||||
int rc;
|
||||
const int gcry_pkalgo = map_pk_openpgp_to_gcry( algo );
|
||||
|
||||
*result = NULL;
|
||||
/* make a sexp from skey */
|
||||
if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
|
||||
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 (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_E)
|
||||
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)
|
||||
{
|
||||
char *curve = openpgp_oid_to_str (skey[0]);
|
||||
if (!curve)
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
rc = gcry_sexp_build (&s_skey, NULL,
|
||||
"(private-key(ecdsa(curve%s)(q%m)(d%m)))",
|
||||
curve, skey[1], skey[2]);
|
||||
xfree (curve);
|
||||
}
|
||||
}
|
||||
else
|
||||
return GPG_ERR_PUBKEY_ALGO;
|
||||
|
||||
if (rc)
|
||||
BUG ();
|
||||
|
||||
/* put data into a S-Exp s_data */
|
||||
if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
|
||||
if (!rc)
|
||||
{
|
||||
if (!data[0] || !data[1])
|
||||
rc = gpg_error (GPG_ERR_BAD_MPI);
|
||||
else
|
||||
rc = gcry_sexp_build (&s_data, NULL,
|
||||
"(enc-val(elg(a%m)(b%m)))", data[0], data[1]);
|
||||
rc = gcry_pk_testkey (s_skey);
|
||||
gcry_sexp_release (s_skey);
|
||||
}
|
||||
else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_E)
|
||||
{
|
||||
if (!data[0])
|
||||
rc = gpg_error (GPG_ERR_BAD_MPI);
|
||||
else
|
||||
rc = gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", data[0]);
|
||||
}
|
||||
else
|
||||
BUG ();
|
||||
|
||||
if (rc)
|
||||
BUG ();
|
||||
|
||||
rc = gcry_pk_decrypt (&s_plain, s_data, s_skey);
|
||||
gcry_sexp_release (s_skey);
|
||||
gcry_sexp_release (s_data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
*result = gcry_sexp_nth_mpi (s_plain, 0, 0);
|
||||
gcry_sexp_release (s_plain);
|
||||
if (!*result)
|
||||
return -1; /* oops */
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
26
g10/pkglue.h
26
g10/pkglue.h
@ -1,5 +1,5 @@
|
||||
/* pkglue.h - public key operations definitions
|
||||
* Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2003, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -20,13 +20,31 @@
|
||||
#ifndef GNUPG_G10_PKGLUE_H
|
||||
#define GNUPG_G10_PKGLUE_H
|
||||
|
||||
#include "packet.h" /* For PKT_public_key. */
|
||||
|
||||
/*-- pkglue.c --*/
|
||||
gcry_mpi_t mpi_from_sexp (gcry_sexp_t sexp, const char * item);
|
||||
|
||||
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,
|
||||
gcry_mpi_t *pkey);
|
||||
int pk_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
|
||||
gcry_mpi_t *skey);
|
||||
PKT_public_key *pk, gcry_mpi_t *pkey);
|
||||
int pk_check_secret_key (int algo, gcry_mpi_t *skey);
|
||||
|
||||
|
||||
/*-- ecdh.c --*/
|
||||
gcry_mpi_t pk_ecdh_default_params (unsigned int qbits);
|
||||
gpg_error_t pk_ecdh_generate_ephemeral_key (gcry_mpi_t *pkey, gcry_mpi_t *r_k);
|
||||
gpg_error_t 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);
|
||||
|
||||
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 shared, gcry_mpi_t * skey);
|
||||
|
||||
|
||||
#endif /*GNUPG_G10_PKGLUE_H*/
|
||||
|
@ -145,6 +145,9 @@ 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;
|
||||
const int pkalgo = map_pk_openpgp_to_gcry (sk->pubkey_algo);
|
||||
|
||||
/* Get the keygrip. */
|
||||
err = hexkeygrip_from_pk (sk, &keygrip);
|
||||
@ -152,7 +155,7 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
|
||||
goto leave;
|
||||
|
||||
/* Convert the data to an S-expression. */
|
||||
if (sk->pubkey_algo == GCRY_PK_ELG || sk->pubkey_algo == GCRY_PK_ELG_E)
|
||||
if (pkalgo == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E)
|
||||
{
|
||||
if (!enc->data[0] || !enc->data[1])
|
||||
err = gpg_error (GPG_ERR_BAD_MPI);
|
||||
@ -160,7 +163,7 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
|
||||
err = gcry_sexp_build (&s_data, NULL, "(enc-val(elg(a%m)(b%m)))",
|
||||
enc->data[0], enc->data[1]);
|
||||
}
|
||||
else if (sk->pubkey_algo == GCRY_PK_RSA || sk->pubkey_algo == GCRY_PK_RSA_E)
|
||||
else if (pkalgo == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_E)
|
||||
{
|
||||
if (!enc->data[0])
|
||||
err = gpg_error (GPG_ERR_BAD_MPI);
|
||||
@ -168,12 +171,26 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
|
||||
err = gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))",
|
||||
enc->data[0]);
|
||||
}
|
||||
else if (pkalgo == GCRY_PK_ECDH)
|
||||
{
|
||||
if (!enc->data[0] || !enc->data[1])
|
||||
err = gpg_error (GPG_ERR_BAD_MPI);
|
||||
else
|
||||
err = gcry_sexp_build (&s_data, NULL, "(enc-val(ecdh(s%m)(e%m)))",
|
||||
enc->data[0], enc->data[1]);
|
||||
}
|
||||
else
|
||||
err = gpg_error (GPG_ERR_BUG);
|
||||
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
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);
|
||||
@ -202,32 +219,74 @@ 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 (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
if (n + 7 > nframe)
|
||||
gcry_mpi_t shared_mpi;
|
||||
gcry_mpi_t decoded;
|
||||
|
||||
/* At the beginning the frame are the bytes of shared point MPI. */
|
||||
err = gcry_mpi_scan (&shared_mpi, GCRYMPI_FMT_USG, frame, nframe, NULL);
|
||||
if (err)
|
||||
{
|
||||
err = gpg_error (G10ERR_WRONG_SECKEY);
|
||||
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
||||
goto leave;
|
||||
}
|
||||
if (frame[n] == 1 && frame[nframe - 1] == 2)
|
||||
|
||||
err = pk_ecdh_decrypt (&decoded, fp, enc->data[1]/*encr data as an MPI*/,
|
||||
shared_mpi, sk->pkey);
|
||||
mpi_release (shared_mpi);
|
||||
if(err)
|
||||
goto leave;
|
||||
|
||||
/* Reuse NFRAME, which size is sufficient to include the session key. */
|
||||
err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &nframe, decoded);
|
||||
mpi_release (decoded);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Now the frame are the bytes decrypted but padded session key. */
|
||||
|
||||
/* Allow double padding for the benefit of DEK size concealment.
|
||||
Higher than this is wasteful. */
|
||||
if (!nframe || frame[nframe-1] > 8*2 || nframe <= 8
|
||||
|| frame[nframe-1] > nframe)
|
||||
{
|
||||
log_info (_("old encoding of the DEK is not supported\n"));
|
||||
err = gpg_error (G10ERR_CIPHER_ALGO);
|
||||
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
||||
goto leave;
|
||||
}
|
||||
if (frame[n] != 2) /* Something went wrong. */
|
||||
nframe -= frame[nframe-1]; /* Remove padding. */
|
||||
assert (!n); /* (used just below) */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!card)
|
||||
{
|
||||
err = gpg_error (G10ERR_WRONG_SECKEY);
|
||||
goto leave;
|
||||
if (n + 7 > nframe)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_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 (GPG_ERR_CIPHER_ALGO);
|
||||
goto leave;
|
||||
}
|
||||
if (frame[n] != 2) /* Something went wrong. */
|
||||
{
|
||||
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
||||
goto leave;
|
||||
}
|
||||
for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes. */
|
||||
;
|
||||
n++; /* Skip the zero byte. */
|
||||
}
|
||||
for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes. */
|
||||
;
|
||||
n++; /* Skip the zero byte. */
|
||||
}
|
||||
|
||||
if (n + 4 > nframe)
|
||||
{
|
||||
err = gpg_error (G10ERR_WRONG_SECKEY);
|
||||
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
234
g10/seskey.c
234
g10/seskey.c
@ -1,6 +1,6 @@
|
||||
/* seskey.c - make sesssion keys etc.
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
* 2006, 2009 Free Software Foundation, Inc.
|
||||
* 2006, 2009, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -27,6 +27,7 @@
|
||||
#include "gpg.h"
|
||||
#include "util.h"
|
||||
#include "cipher.h"
|
||||
#include "options.h"
|
||||
#include "main.h"
|
||||
#include "i18n.h"
|
||||
|
||||
@ -73,81 +74,127 @@ 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;
|
||||
gcry_mpi_t a;
|
||||
size_t nframe = (nbits+7) / 8;
|
||||
byte *p;
|
||||
byte *frame;
|
||||
int i,n;
|
||||
u16 csum;
|
||||
gcry_mpi_t a;
|
||||
|
||||
/* The current limitation is that we can only use a session key
|
||||
* whose length is a multiple of BITS_PER_MPI_LIMB
|
||||
* I think we can live with that.
|
||||
*/
|
||||
if( dek->keylen + 7 > nframe || !nframe )
|
||||
log_bug("can't encode a %d bit key in a %d bits frame\n",
|
||||
dek->keylen*8, nbits );
|
||||
if (DBG_CIPHER)
|
||||
log_debug ("encode_session_key: encoding %d byte DEK", dek->keylen);
|
||||
|
||||
/* We encode the session key in this way:
|
||||
*
|
||||
* 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes)
|
||||
*
|
||||
* (But how can we store the leading 0 - the external representaion
|
||||
* of MPIs doesn't allow leading zeroes =:-)
|
||||
*
|
||||
* RND are non-zero random bytes.
|
||||
* A is the cipher algorithm
|
||||
* DEK is the encryption key (session key) length k depends on the
|
||||
* cipher algorithm (20 is used with blowfish160).
|
||||
* CSUM is the 16 bit checksum over the DEK
|
||||
*/
|
||||
csum = 0;
|
||||
for( p = dek->key, i=0; i < dek->keylen; i++ )
|
||||
csum += *p++;
|
||||
csum = 0;
|
||||
for (p = dek->key, i=0; i < dek->keylen; i++)
|
||||
csum += *p++;
|
||||
|
||||
frame = xmalloc_secure( nframe );
|
||||
n = 0;
|
||||
frame[n++] = 0;
|
||||
frame[n++] = 2;
|
||||
i = nframe - 6 - dek->keylen;
|
||||
assert( i > 0 );
|
||||
p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
|
||||
/* Replace zero bytes by new values. */
|
||||
for(;;) {
|
||||
int j, k;
|
||||
byte *pp;
|
||||
/* 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));
|
||||
|
||||
/* count the zero bytes */
|
||||
for(j=k=0; j < i; j++ )
|
||||
if( !p[j] )
|
||||
k++;
|
||||
if( !k )
|
||||
break; /* okay: no zero bytes */
|
||||
k += k/128 + 3; /* better get some more */
|
||||
pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
|
||||
for(j=0; j < i && k ;) {
|
||||
if( !p[j] )
|
||||
p[j] = pp[--k];
|
||||
if (p[j])
|
||||
j++;
|
||||
}
|
||||
xfree(pp);
|
||||
/* alg+key+csum fit and the size is congruent to 8. */
|
||||
assert (!(nframe%8) && nframe > 1 + dek->keylen + 2 );
|
||||
|
||||
frame = xmalloc_secure (nframe);
|
||||
n = 0;
|
||||
frame[n++] = dek->algo;
|
||||
memcpy (frame+n, dek->key, dek->keylen);
|
||||
n += dek->keylen;
|
||||
frame[n++] = csum >> 8;
|
||||
frame[n++] = csum;
|
||||
i = nframe - n; /* Number of padded bytes. */
|
||||
memset (frame+n, i, i); /* Use it as the value of each padded byte. */
|
||||
assert (n+i == nframe);
|
||||
|
||||
if (DBG_CIPHER)
|
||||
log_debug ("encode_session_key: "
|
||||
"[%d] %02x %02x %02x ... %02x %02x %02x\n",
|
||||
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;
|
||||
}
|
||||
memcpy( frame+n, p, i );
|
||||
xfree(p);
|
||||
n += i;
|
||||
frame[n++] = 0;
|
||||
frame[n++] = dek->algo;
|
||||
memcpy( frame+n, dek->key, dek->keylen ); n += dek->keylen;
|
||||
frame[n++] = csum >>8;
|
||||
frame[n++] = csum;
|
||||
assert( n == nframe );
|
||||
if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, n, &nframe))
|
||||
BUG();
|
||||
xfree(frame);
|
||||
return a;
|
||||
|
||||
/* The current limitation is that we can only use a session key
|
||||
* whose length is a multiple of BITS_PER_MPI_LIMB
|
||||
* I think we can live with that.
|
||||
*/
|
||||
if (dek->keylen + 7 > nframe || !nframe)
|
||||
log_bug ("can't encode a %d bit key in a %d bits frame\n",
|
||||
dek->keylen*8, nbits );
|
||||
|
||||
/* We encode the session key in this way:
|
||||
*
|
||||
* 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes)
|
||||
*
|
||||
* (But how can we store the leading 0 - the external representaion
|
||||
* of MPIs doesn't allow leading zeroes =:-)
|
||||
*
|
||||
* RND are non-zero random bytes.
|
||||
* A is the cipher algorithm
|
||||
* DEK is the encryption key (session key) length k depends on the
|
||||
* cipher algorithm (20 is used with blowfish160).
|
||||
* CSUM is the 16 bit checksum over the DEK
|
||||
*/
|
||||
|
||||
frame = xmalloc_secure( nframe );
|
||||
n = 0;
|
||||
frame[n++] = 0;
|
||||
frame[n++] = 2;
|
||||
i = nframe - 6 - dek->keylen;
|
||||
assert( i > 0 );
|
||||
p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
|
||||
/* Replace zero bytes by new values. */
|
||||
for (;;)
|
||||
{
|
||||
int j, k;
|
||||
byte *pp;
|
||||
|
||||
/* Count the zero bytes. */
|
||||
for (j=k=0; j < i; j++ )
|
||||
if (!p[j])
|
||||
k++;
|
||||
if (!k)
|
||||
break; /* Okay: no zero bytes. */
|
||||
k += k/128 + 3; /* Better get some more. */
|
||||
pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
|
||||
for (j=0; j < i && k ;)
|
||||
{
|
||||
if (!p[j])
|
||||
p[j] = pp[--k];
|
||||
if (p[j])
|
||||
j++;
|
||||
}
|
||||
xfree (pp);
|
||||
}
|
||||
memcpy (frame+n, p, i);
|
||||
xfree (p);
|
||||
n += i;
|
||||
frame[n++] = 0;
|
||||
frame[n++] = dek->algo;
|
||||
memcpy (frame+n, dek->key, dek->keylen );
|
||||
n += dek->keylen;
|
||||
frame[n++] = csum >>8;
|
||||
frame[n++] = csum;
|
||||
assert (n == nframe);
|
||||
if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, n, &nframe))
|
||||
BUG();
|
||||
xfree (frame);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
@ -161,8 +208,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,19 +256,27 @@ gcry_mpi_t
|
||||
encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
|
||||
{
|
||||
gcry_mpi_t frame;
|
||||
int pkalgo;
|
||||
|
||||
assert (hash_algo);
|
||||
assert (pk);
|
||||
|
||||
if (pk->pubkey_algo == GCRY_PK_DSA)
|
||||
pkalgo = map_pk_openpgp_to_gcry (pk->pubkey_algo);
|
||||
|
||||
if (pkalgo == GCRY_PK_DSA || pkalgo == GCRY_PK_ECDSA)
|
||||
{
|
||||
/* It's a DSA signature, so find out the size of q. */
|
||||
/* It's a DSA signature, so find out the size of q. */
|
||||
|
||||
size_t qbytes = gcry_mpi_get_nbits (pk->pkey[1]);
|
||||
|
||||
/* pkey[1] is Q for ECDSA, which is an uncompressed point,
|
||||
i.e. 04 <x> <y> */
|
||||
if (pkalgo == GCRY_PK_ECDSA)
|
||||
qbytes = ecdsa_qbits_from_Q (qbytes);
|
||||
|
||||
/* Make sure it is a multiple of 8 bits. */
|
||||
|
||||
if(qbytes%8)
|
||||
if (qbytes%8)
|
||||
{
|
||||
log_error(_("DSA requires the hash length to be a"
|
||||
" multiple of 8 bits\n"));
|
||||
@ -236,22 +291,39 @@ 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"),
|
||||
keystr_from_pk (pk), qbytes);
|
||||
log_error (_("%s key %s uses an unsafe (%zu bit) hash\n"),
|
||||
gcry_pk_algo_name (pkalgo), keystr_from_pk (pk), qbytes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qbytes /= 8;
|
||||
|
||||
/* 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)
|
||||
automatically left-truncate.
|
||||
|
||||
FIXME: Check against FIPS.
|
||||
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)
|
||||
< ((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 "
|
||||
"(hash is %s\n"),
|
||||
gcry_pk_algo_name (pkalgo),
|
||||
keystr_from_pk(pk), qbytes*8,
|
||||
gcry_md_algo_name (hash_algo));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* By passing QBYTES as length to mpi_scan, we do the truncation
|
||||
of the hash.
|
||||
|
||||
Note that in case of ECDSA 521 the hash is always smaller
|
||||
than the key size. */
|
||||
if (gcry_mpi_scan (&frame, GCRYMPI_FMT_USG,
|
||||
gcry_md_read (md, hash_algo), qbytes, &qbytes))
|
||||
BUG();
|
||||
|
44
g10/sign.c
44
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,14 @@ 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 +925,15 @@ 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 */
|
||||
@ -1490,11 +1485,14 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
|
||||
|
||||
if(opt.cert_digest_algo)
|
||||
digest_algo=opt.cert_digest_algo;
|
||||
else if(pksk->pubkey_algo==PUBKEY_ALGO_RSA
|
||||
else if(pksk->pubkey_algo == PUBKEY_ALGO_RSA
|
||||
&& pk->version<4 && sigversion<4)
|
||||
digest_algo = DIGEST_ALGO_MD5;
|
||||
else if(pksk->pubkey_algo==PUBKEY_ALGO_DSA)
|
||||
else if(pksk->pubkey_algo == PUBKEY_ALGO_DSA)
|
||||
digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8);
|
||||
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;
|
||||
}
|
||||
|
@ -40,6 +40,5 @@ const void *next_tuple (tupledesc_t tupledesc,
|
||||
unsigned int *r_tag, size_t *r_length);
|
||||
|
||||
|
||||
|
||||
#endif /*G13_UTILS_H*/
|
||||
|
||||
|
@ -1,3 +1,14 @@
|
||||
2011-02-01 Werner Koch <wk@g10code.com>
|
||||
|
||||
* cipher.h (PUBKEY_MAX_NPKEY, PUBKEY_MAX_NSKEY): Bump up to
|
||||
accommodate gcrypt ECC keys.
|
||||
|
||||
2011-01-21 Werner Koch <wk@g10code.com>
|
||||
|
||||
* cipher.h (GCRY_PK_USAGE_CERT): Remove compatibility macros
|
||||
because we now require libgcrypt 1.4.6.
|
||||
(GCRY_PK_ECDH): Add replacement.
|
||||
|
||||
2009-08-20 Daiki Ueno <ueno@unixuser.org> (wk)
|
||||
|
||||
* cipher.h (struct DEK): Add field S2K_CACHEID.
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* cipher.h - Definitions for OpenPGP
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2006,
|
||||
* 2007 Free Software Foundation, Inc.
|
||||
* 2007, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -23,10 +23,8 @@
|
||||
#include <gcrypt.h>
|
||||
|
||||
/* Macros for compatibility with older libgcrypt versions. */
|
||||
#ifndef GCRY_PK_USAGE_CERT
|
||||
# define GCRY_PK_USAGE_CERT 4
|
||||
# define GCRY_PK_USAGE_AUTH 8
|
||||
# define GCRY_PK_USAGE_UNKN 128
|
||||
#ifndef HAVE_GCRY_PK_ECDH
|
||||
# define GCRY_PK_ECDH 302
|
||||
#endif
|
||||
|
||||
|
||||
@ -56,6 +54,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
|
||||
#define PUBKEY_ALGO_ECDSA 19
|
||||
#define PUBKEY_ALGO_ELGAMAL /* 20 */ GCRY_PK_ELG /* Elgamal encr+sign */
|
||||
|
||||
#define PUBKEY_USAGE_SIG GCRY_PK_USAGE_SIGN /* Good for signatures. */
|
||||
@ -100,8 +100,8 @@ typedef struct
|
||||
|
||||
|
||||
/* Constants to allocate static MPI arrays. */
|
||||
#define PUBKEY_MAX_NPKEY 4
|
||||
#define PUBKEY_MAX_NSKEY 6
|
||||
#define PUBKEY_MAX_NPKEY 5
|
||||
#define PUBKEY_MAX_NSKEY 7
|
||||
#define PUBKEY_MAX_NSIG 2
|
||||
#define PUBKEY_MAX_NENC 2
|
||||
|
||||
|
@ -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,12 @@ parse_key (const unsigned char *data, size_t datalen,
|
||||
case 17: /* DSA */
|
||||
npkey = 4;
|
||||
break;
|
||||
case 18: /* ECDH */
|
||||
npkey = 3;
|
||||
break;
|
||||
case 19: /* ECDSA */
|
||||
npkey = 2;
|
||||
break;
|
||||
default: /* Unknown algorithm. */
|
||||
return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
|
||||
no-creation-time.gpg A key with a zero creation time.
|
||||
|
||||
ecc-sample-1-pub.asc The first ECC sample key.
|
||||
ecc-sample-1-sec.asc The first ECC sample key (secret).
|
||||
|
||||
|
22
tests/openpgp/samplekeys/ecc-sample-1-pub.asc
Normal file
22
tests/openpgp/samplekeys/ecc-sample-1-pub.asc
Normal file
@ -0,0 +1,22 @@
|
||||
The key has been generated by the first GnuPG ECC version at
|
||||
http://code.google.com/p/gnupg-ecc.
|
||||
|
||||
The sample key has ECDSA top key 0xBAA59D9C and a single ECDH
|
||||
encryption subkey 0x4089AB73. ECDH subkey uses SHA-256 and AES-128
|
||||
with KDF.
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v2.1.0-ecc (GNU/Linux)
|
||||
|
||||
mFIETJPQrRMIKoZIzj0DAQcCAwQLx6e669XwjHTHe3HuROe7C1oYMXuZbaU5PjOs
|
||||
xSkyxtL2D00e/jWgufuNN4ftS+6XygEtB7j1g1vnCTVF1TLmtCRlY19kc2FfZGhf
|
||||
MjU2IDxvcGVucGdwQGJyYWluaHViLm9yZz6IegQTEwgAIgUCTJPQrQIbAwYLCQgH
|
||||
AwIGFQgCCQoLBBYCAwECHgECF4AACgkQC6Ut8LqlnZzmXQEAiKgiSzPSpUOJcX9d
|
||||
JtLJ5As98Alit2oFwzhxG7mSVmQA/RP67yOeoUtdsK6bwmRA95cwf9lBIusNjehx
|
||||
XDfpHj+/uFYETJPQrRIIKoZIzj0DAQcCAwR/cMCoGEzcrqXbILqP7Rfke977dE1X
|
||||
XsRJEwrzftreZYrn7jXSDoiXkRyfVkvjPZqUvB5cknsaoH/3UNLRHClxAwEIB4hh
|
||||
BBgTCAAJBQJMk9CtAhsMAAoJEAulLfC6pZ2c1yYBAOSUmaQ8rkgihnepbnpK7tNz
|
||||
3QEocsLEtsTCDUBGNYGyAQDclifYqsUChXlWKaw3md+yHJPcWZXzHt37c4q/MhIm
|
||||
oQ==
|
||||
=hMzp
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
25
tests/openpgp/samplekeys/ecc-sample-1-sec.asc
Normal file
25
tests/openpgp/samplekeys/ecc-sample-1-sec.asc
Normal file
@ -0,0 +1,25 @@
|
||||
The key has been generated by the first GnuPG ECC version at
|
||||
http://code.google.com/p/gnupg-ecc.
|
||||
|
||||
The sample key has ECDSA top key 0xBAA59D9C and a single ECDH
|
||||
encryption subkey 0x4089AB73. ECDH subkey uses SHA-256 and AES-128
|
||||
with KDF. The password for the key is "ecc".
|
||||
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
Version: GnuPG v2.1.0-ecc (GNU/Linux)
|
||||
|
||||
lJ0ETJPQrRMIKoZIzj0DAQcCAwQLx6e669XwjHTHe3HuROe7C1oYMXuZbaU5PjOs
|
||||
xSkyxtL2D00e/jWgufuNN4ftS+6XygEtB7j1g1vnCTVF1TLm/gMDAmHomSLb9NbE
|
||||
oyWUoqgKTbZzbFR/SWmiCcuiQEhREcTyvyU1hAglj7FsBJoQ6/pbeAEQZ3bVzlNM
|
||||
8F0nF8KPLPuEADF1+4CntCRlY19kc2FfZGhfMjU2IDxvcGVucGdwQGJyYWluaHVi
|
||||
Lm9yZz6IegQTEwgAIgUCTJPQrQIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
|
||||
CgkQC6Ut8LqlnZzmXQEAiKgiSzPSpUOJcX9dJtLJ5As98Alit2oFwzhxG7mSVmQA
|
||||
/RP67yOeoUtdsK6bwmRA95cwf9lBIusNjehxXDfpHj+/nKEETJPQrRIIKoZIzj0D
|
||||
AQcCAwR/cMCoGEzcrqXbILqP7Rfke977dE1XXsRJEwrzftreZYrn7jXSDoiXkRyf
|
||||
VkvjPZqUvB5cknsaoH/3UNLRHClxAwEIB/4DAwJh6Jki2/TWxKO7gHKWIcOcxYZp
|
||||
CRWjlUghbKb6Q83p8GLPjKRN0USl/U1tObWdksqMXhUO0ePLWUnrbwoWYfYXg9Er
|
||||
ADTgCYhhBBgTCAAJBQJMk9CtAhsMAAoJEAulLfC6pZ2c1yYA/3eJRirPQZmBno+Z
|
||||
P/HOBSFWmFt4cUBGUx3oqiUd5loOAP480pb+vXx9ipljJWCJDSl/boRSuqB4hePP
|
||||
qt9Rd5gNdQ==
|
||||
=O8Dg
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
Loading…
x
Reference in New Issue
Block a user