Merge branch 'ECC-INTEGRATION-2-1'

This commit is contained in:
Werner Koch 2011-02-03 16:39:03 +01:00
commit 38904b697c
51 changed files with 3136 additions and 3033 deletions

132
.gitignore vendored
View File

@ -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

View File

@ -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.

View File

@ -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.

18
NEWS
View File

@ -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)
-----------------------------------------------------
@ -183,7 +185,7 @@ Noteworthy changes in version 2.0.10 (2009-01-12)
the installation directory to %CSIDL_COMMON_APPDATA%/GNU/etc/gnupg.
* [w32] The gnupg2.nls directory is not anymore used. The standard
locale directory is now used.
locale directory is now used.
* [w32] Fixed a race condition between gpg and gpgsm in the use of
temporary file names.
@ -235,7 +237,7 @@ Noteworthy changes in version 2.0.8 (2007-12-20)
* The envvars XAUTHORITY and PINENTRY_USER_DATA are now passed to the
Pinentry.
* Fixed the auto creation of the key stub for smartcards.
* Fixed the auto creation of the key stub for smartcards.
* Fixed a rare bug in decryption using the OpenPGP card.
@ -277,7 +279,7 @@ Noteworthy changes in version 2.0.6 (2007-08-16)
* GPGSM does now grok --default-key.
* GPGCONF is now aware of --default-key and --encrypt-to.
* GPGCONF is now aware of --default-key and --encrypt-to.
* GPGSM does again correctly print the serial number as well the the
various keyids. This was broken since 2.0.4.
@ -286,7 +288,7 @@ Noteworthy changes in version 2.0.6 (2007-08-16)
* Improved Windows support.
Noteworthy changes in version 2.0.5 (2007-07-05)
------------------------------------------------
@ -326,7 +328,7 @@ Noteworthy changes in version 2.0.3 (2007-03-08)
such messages by default which makes those programs safe again.
--allow-multiple-messages returns to the old behavior. [CVE-2007-1263].
* New --verify-option show-primary-uid-only.
* New --verify-option show-primary-uid-only.
* gpgconf may now reads a global configuration file to select which
options are changeable by a frontend. The new applygnupgdefaults
@ -490,7 +492,7 @@ Noteworthy changes in version 1.9.21 (2006-06-20)
* Support for the CardMan 4040 PCMCIA reader (Linux 2.6.15 required).
* Scdaemon does not anymore reset cards at the end of a connection.
* Scdaemon does not anymore reset cards at the end of a connection.
* Kludge to allow use of Bundesnetzagentur issued X.509 certificates.
@ -510,7 +512,7 @@ Noteworthy changes in version 1.9.20 (2005-12-20)
* Basic support for qualified signatures.
* New debug tool gpgparsemail.
* New debug tool gpgparsemail.
Noteworthy changes in version 1.9.19 (2005-09-12)
@ -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

View File

@ -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
@ -510,7 +545,7 @@
* genkey.c (agent_protect_and_store): Return RC and not 0.
* protect.c (do_encryption): Fix ignored error code from malloc.
Reported by Fabian Keil.
2009-06-17 Werner Koch <wk@g10code.com>
* call-pinentry.c (agent_get_confirmation): Add arg WITH_CANCEL.
@ -534,7 +569,7 @@
* trustlist.c: Include estream.h.
(agent_marktrusted): Replace stdio stream by estream functions.
* protect-tool.c (store_private_key): Use bin2hex.
* protect-tool.c (store_private_key): Use bin2hex.
2009-06-02 Werner Koch <wk@g10code.com>
@ -548,7 +583,7 @@
2009-05-15 Werner Koch <wk@g10code.com>
Fix bug #1053.
* agent.h (lookup_ttl_t): New.
* findkey.c (unprotect): Add arg LOOKUP_TTL.
(agent_key_from_file): Ditto.
@ -626,7 +661,7 @@
(agent_istrusted): Add arg R_DISABLED. Change all callers.
(agent_marktrusted): Do not ask if flagged as disabled. Reverse
the order of the questions. Store the disabled flag.
* gpg-agent.c (main): Save signal mask and open fds. Restore mask
and close all fds prior to the exec. Fixes bug#1013.
@ -737,11 +772,11 @@
* command.c (cmd_geteventcounter): Mark unused arg.
(cmd_listtrusted, cmd_pksign, cmd_pkdecrypt, cmd_genkey): Ditto.
(cmd_updatestartuptty, post_cmd_notify): Ditto.
* command-ssh.c (add_control_entry)
(ssh_handler_request_identities, ssh_handler_remove_identity)
(ssh_handler_remove_all_identities, ssh_handler_lock)
* command-ssh.c (add_control_entry)
(ssh_handler_request_identities, ssh_handler_remove_identity)
(ssh_handler_remove_all_identities, ssh_handler_lock)
(ssh_handler_unlock): Ditto.
* call-pinentry.c (pinentry_active_p, popup_message_thread)
* call-pinentry.c (pinentry_active_p, popup_message_thread)
(agent_popup_message_stop): Ditto.
* findkey.c (agent_public_key_from_file): Ditto.
* genkey.c (check_passphrase_pattern): Ditto.
@ -860,7 +895,7 @@
* agent.h (struct server_control_s): Add XAUTHORITY and
PINENTRY_USER_DATA.
* gpg-agent.c: New option --xauthority.
(main, agent_init_default_ctrl)
(main, agent_init_default_ctrl)
(agent_deinit_default_ctrl): Implemented
* command.c (cmd_updatestartuptty): Ditto.
* command-ssh.c (start_command_handler_ssh): Ditto.
@ -1020,7 +1055,7 @@
2007-06-21 Werner Koch <wk@g10code.com>
* agent.h (ctrl_t): Remove. It is now declared in ../common/util.h.
* agent.h (ctrl_t): Remove. It is now declared in ../common/util.h.
* gpg-agent.c (check_for_running_agent): New arg SILENT. Changed
all callers.
@ -1053,7 +1088,7 @@
* preset-passphrase.c (main): Setup default socket name for
simple-pwquery.
(map_spwq_error): Remove.
(MAP_SPWQ_ERROR_IMPL): New.
(MAP_SPWQ_ERROR_IMPL): New.
* call-pinentry.c (start_pinentry): Use gnupg_module_name.
* call-scd.c (start_scd): Ditto.
@ -1115,7 +1150,7 @@
(main): Call the setup_libgcrypt_logging helper.
* protect-tool.c (my_gcry_logger): Removed.
(main): Call the setup_libgcrypt_logging helper.
2007-04-03 Werner Koch <wk@g10code.com>
* trustlist.c (read_trustfiles): Take a missing trustlist as an
@ -1123,7 +1158,7 @@
2007-03-20 Werner Koch <wk@g10code.com>
* protect-tool.c: New option --p12-charset.
* protect-tool.c: New option --p12-charset.
* minip12.c (p12_build): Implement it.
2007-03-19 Werner Koch <wk@g10code.com>
@ -1158,7 +1193,7 @@
2007-01-31 Werner Koch <wk@g10code.com>
* command-ssh.c (start_command_handler_ssh):
* command-ssh.c (start_command_handler_ssh):
* Makefile.am (t_common_ldadd): Add LIBICONV.
@ -1286,7 +1321,7 @@
(agent_pksign_do): Use it here for the TLS algo.
* agent.h (GCRY_MD_USER_TLS_MD5SHA1): New.
* divert-scd.c (pksign): Add case for tls-md5sha1.
* divert-scd.c (encode_md_for_card): Check that the algo is valid.
2006-10-04 Werner Koch <wk@g10code.com>
@ -1356,7 +1391,7 @@
Replaced all Assuan error codes by libgpg-error codes. Removed
all map_to_assuan_status and map_assuan_err.
* gpg-agent.c (main): Call assuan_set_assuan_err_source to have Assuan
switch to gpg-error codes.
* command.c (set_error): Adjusted.
@ -1400,7 +1435,7 @@
* minip12.c (oid_pkcs_12_keyBag): New.
(parse_bag_encrypted_data): New arg R_RESULT. Support keybags and
return the key object.
return the key object.
(p12_parse): Take new arg into account. Free RESULT on error.
2006-06-26 Werner Koch <wk@g10code.com>
@ -1468,7 +1503,7 @@
* call-scd.c (inq_needpin): Reworked to support the new KEYPADINFO.
* query.c (start_pinentry): Keep track of the owner.
(popup_message_thread, agent_popup_message_start)
(popup_message_thread, agent_popup_message_start)
(agent_popup_message_stop, agent_reset_query): New.
* command.c (start_command_handler): Make sure a popup window gets
closed.
@ -1519,7 +1554,7 @@
2005-06-21 Werner Koch <wk@g10code.com>
* minip12.c (create_final): Cast size_t to ulong for printf.
* minip12.c (create_final): Cast size_t to ulong for printf.
(build_key_bag, build_cert_bag, build_cert_sequence): Ditto.
2005-06-16 Werner Koch <wk@g10code.com>
@ -1534,7 +1569,7 @@
* protect.c (do_encryption): Ditto.
(do_encryption): Made arg PROTBEGIN unsigned. Initialize RESULT
and RESULTLEN even on error.
(merge_lists): Need to cast unsigned char * for strcpy. Initialize
(merge_lists): Need to cast unsigned char * for strcpy. Initialize
RESULTand RESULTLEN even on error.
(agent_unprotect): Likewise for strtoul.
(make_shadow_info): Made P and INFO plain char.
@ -1594,7 +1629,7 @@
* command.c (cmd_updatestartuptty): New.
* gpg-agent.c: New option --write-env-file.
* gpg-agent.c (handle_connections): Make sure that the signals we
are handling are not blocked.Block signals while creating new
threads.
@ -1864,8 +1899,8 @@
(make_cstring): Ditto.
(data_sign): Don't use a variable for the passphrase prompt, make
it translatable.
(ssh_request_process):
(ssh_request_process):
* findkey.c (modify_description): Renamed arguments for clarity,
polished documentation. Make comment a C-string. Fixed case of
@ -1991,7 +2026,7 @@
2004-12-21 Werner Koch <wk@g10code.com>
* gpg-agent.c (main): Use default_homedir().
* protect-tool.c (main): Ditto.
* protect-tool.c (main): Ditto.
2004-12-20 Werner Koch <wk@g10code.com>
@ -2017,7 +2052,7 @@
* query.c (initialize_module_query): New.
* call-scd.c (initialize_module_call_scd): New.
* gpg-agent.c (main): Call them.
2004-12-18 Werner Koch <wk@g10code.com>
* gpg-agent.c (main): Remove special Pth initialize.
@ -2069,10 +2104,10 @@
to Moritz for pointing this out.
2004-09-25 Moritz Schulte <moritz@g10code.com>
* agent.h: Declare: agent_pksign_do.
(struct server_control_s): New member: raw_value.
* pksign.c (do_encode_md): New argument: raw_value; support
generation of raw (non-pkcs1) data objects; adjust callers.
(agent_pksign_do): New function, based on code ripped
@ -2080,7 +2115,7 @@
(agent_pksign): Use agent_pksign_do.
* command.c (start_command_handler): Set ctrl.digest.raw_value.
2004-09-09 Werner Koch <wk@g10code.de>
* gpg-agent.c (check_for_running_agent): New.
@ -2121,14 +2156,14 @@
* gpg-agent.c (handle_signal): Reload the trustlist on SIGHUP.
(start_connection_thread): Hack to simulate a ticker.
* trustlist.c (agent_trustlist_housekeeping)
* trustlist.c (agent_trustlist_housekeeping)
(agent_reload_trustlist): New. Protected all global functions
here with a simple counter which is sufficient for Pth.
2004-05-03 Werner Koch <wk@gnupg.org>
* gpg-agent.c: Remove help texts for options lile --lc-ctype.
(main): New option --allow-mark-trusted.
(main): New option --allow-mark-trusted.
* trustlist.c (agent_marktrusted): Use it here.
2004-04-30 Werner Koch <wk@gnupg.org>
@ -2201,7 +2236,7 @@
string. Changed all callers.
* minip12.c: Revamped the build part.
(p12_build): New args CERT and CERTLEN.
(p12_build): New args CERT and CERTLEN.
2004-02-18 Werner Koch <wk@gnupg.org>
@ -2295,7 +2330,7 @@
* findkey.c (agent_key_from_file): Now return an error code so
that we have more detailed error messages in the upper layers.
This fixes the handling of pinentry's cancel button.
This fixes the handling of pinentry's cancel button.
* pksign.c (agent_pksign): Changed accordingly.
* pkdecrypt.c (agent_pkdecrypt): Ditto.
* command.c (cmd_passwd): Ditto.
@ -2322,12 +2357,12 @@
* pksign.c (do_encode_md): Allocate enough space. Cast md
byte to unsigned char to prevent sign extension.
2003-08-14 Timo Schulz <twoaday@freakmail.de>
* pksign.c (do_encode_md): Due to the fact pkcs#1 padding
is now in Libgcrypt, use the new interface.
2003-07-31 Werner Koch <wk@gnupg.org>
* Makefile.am (gpg_agent_LDADD): Added INTLLIBS.
@ -2377,7 +2412,7 @@
* gpg-agent.c (handle_connections): Adjusted for Pth 2.0
Adjusted for changes in the libgcrypt API. Some more fixes for the
libgpg-error stuff.
libgpg-error stuff.
2003-06-04 Werner Koch <wk@gnupg.org>
@ -2456,11 +2491,11 @@
(agent_askpin,agent_get_passphrase,agent_get_confirmation): Add
CTRL arg and pass it ot start_pinentry.
* command.c (cmd_get_passphrase): Pass CTRL argument.
* trustlist.c (agent_marktrusted): Add CTRL argument
* trustlist.c (agent_marktrusted): Add CTRL argument
* command.c (cmd_marktrusted): Pass CTRL argument
* divert-scd.c (ask_for_card): Add CTRL arg.
* divert-scd.c (ask_for_card): Add CTRL arg.
(divert_pksign,divert_pkdecrypt): Ditto. Changed caller.
(getpin_cb): Use OPAQUE to pass the CTRL variable. Changed both
(getpin_cb): Use OPAQUE to pass the CTRL variable. Changed both
users.
* findkey.c (unprotect): Add CTRL arg.
(agent_key_from_file): Ditto.
@ -2695,7 +2730,7 @@
convert it to hex here.
* findkey.c (agent_write_private_key): New.
* genkey.c (store_key): And use it here.
* pkdecrypt.c (agent_pkdecrypt): Changed the way the diversion is done.
* divert-scd.c (divert_pkdecrypt): Changed interface and
implemented it.
@ -2725,7 +2760,7 @@
* protect.c (snext,sskip,smatch): Moved to
* sexp-parse.h: New file.
* divert-scd.c: New.
2002-02-27 Werner Koch <wk@gnupg.org>
* protect.c (agent_shadow_key): New.
@ -2753,7 +2788,7 @@
* gpg-agent.c: New option --default-cache-ttl.
* cache.c (agent_put_cache): Use it.
* cache.c: Add a few debug outputs.
* protect.c (agent_private_key_type): New.
@ -2761,10 +2796,10 @@
* findkey.c (agent_key_from_file): Use it to decide whether we
have to unprotect a key.
(unprotect): Cache the passphrase.
* findkey.c (agent_key_from_file,agent_key_available): The key
files do now require a ".key" suffix to make a script's life
easier.
easier.
* genkey.c (store_key): Ditto.
2002-01-31 Werner Koch <wk@gnupg.org>
@ -2772,11 +2807,11 @@
* genkey.c (store_key): Protect the key.
(agent_genkey): Ask for the passphrase.
* findkey.c (unprotect): Actually unprotect the key.
* query.c (agent_askpin): Add an optional start_err_text.
* query.c (agent_askpin): Add an optional start_err_text.
2002-01-30 Werner Koch <wk@gnupg.org>
* protect.c: New.
* protect.c: New.
(hash_passphrase): Based on the GnuPG 1.0.6 version.
* protect-tool.c: New
@ -2830,10 +2865,10 @@
* command.c (rc_to_assuan_status): Removed and changed all callers
to use map_to_assuan_status.
2001-12-19 Werner Koch <wk@gnupg.org>
* keyformat.txt: New.
* keyformat.txt: New.
2001-12-19 Marcus Brinkmann <marcus@g10code.de>

View File

@ -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);

View File

@ -28,9 +28,16 @@
#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
struct try_do_unprotect_arg_s
{
int is_v4;
int is_protected;
@ -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;
@ -154,7 +182,7 @@ hash_passphrase_and_set_key (const char *passphrase,
keylen = gcry_cipher_get_algo_keylen (protect_algo);
if (!keylen)
return gpg_error (GPG_ERR_INTERNAL);
key = xtrymalloc_secure (keylen);
if (!key)
return gpg_error_from_syserror ();
@ -174,7 +202,7 @@ static u16
checksum (const unsigned char *p, unsigned int n)
{
u16 a;
for (a=0; n; n-- )
a += *p++;
return a;
@ -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);
@ -241,7 +270,7 @@ do_unprotect (const char *passphrase,
return gpg_error (GPG_ERR_MISSING_VALUE);
if (nskey+1 >= skeysize)
return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
/* Check whether SKEY is at all protected. If it is not protected
merely verify the checksum. */
if (!is_protected)
@ -253,7 +282,7 @@ do_unprotect (const char *passphrase,
{
if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
return gpg_error (GPG_ERR_BAD_SECKEY);
err = gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, skey[i]);
if (!err)
{
@ -270,7 +299,7 @@ do_unprotect (const char *passphrase,
if (err)
return err;
}
if (actual_csum != desired_csum)
return gpg_error (GPG_ERR_CHECKSUM);
return 0;
@ -293,7 +322,7 @@ do_unprotect (const char *passphrase,
s2k_algo, gcry_md_algo_name (s2k_algo));
return gpg_error (GPG_ERR_DIGEST_ALGO);
}
err = gcry_cipher_open (&cipher_hd, protect_algo,
GCRY_CIPHER_MODE_CFB,
(GCRY_CIPHER_SECURE
@ -312,10 +341,10 @@ do_unprotect (const char *passphrase,
{
gcry_cipher_close (cipher_hd);
return err;
}
}
gcry_cipher_setiv (cipher_hd, protect_iv, protect_ivlen);
actual_csum = 0;
if (pkt_version >= 4)
{
@ -348,15 +377,15 @@ do_unprotect (const char *passphrase,
{
/* This is the new SHA1 checksum method to detect tampering
with the key as used by the Klima/Rosa attack. */
desired_csum = 0;
desired_csum = 0;
actual_csum = 1; /* Default to bad checksum. */
if (ndata < 20)
if (ndata < 20)
log_error ("not enough bytes for SHA-1 checksum\n");
else
else
{
gcry_md_hd_t h;
if (gcry_md_open (&h, GCRY_MD_SHA1, 1))
BUG(); /* Algo not available. */
gcry_md_write (h, data, ndata - 20);
@ -366,13 +395,13 @@ do_unprotect (const char *passphrase,
gcry_md_close (h);
}
}
else
else
{
/* Old 16 bit checksum method. */
if (ndata < 2)
{
log_error ("not enough bytes for checksum\n");
desired_csum = 0;
desired_csum = 0;
actual_csum = 1; /* Mark checksum bad. */
}
else
@ -386,7 +415,7 @@ do_unprotect (const char *passphrase,
}
}
}
/* Better check it here. Otherwise the gcry_mpi_scan would fail
because the length may have an arbitrary value. */
if (desired_csum == actual_csum)
@ -437,7 +466,7 @@ do_unprotect (const char *passphrase,
gcry_cipher_close (cipher_hd);
return gpg_error (GPG_ERR_BAD_SECKEY);
}
buffer = xtrymalloc_secure (ndata);
if (!buffer)
{
@ -445,7 +474,7 @@ do_unprotect (const char *passphrase,
gcry_cipher_close (cipher_hd);
return err;
}
gcry_cipher_sync (cipher_hd);
buffer[0] = p[0];
buffer[1] = p[1];
@ -526,7 +555,7 @@ try_do_unprotect_cb (struct pin_entry_info_s *pi)
pointed to by GRIP. On error NULL is stored at all return
arguments. */
gpg_error_t
convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
unsigned char *grip, const char *prompt,
const char *cache_nonce,
unsigned char **r_key, char **r_passphrase)
@ -594,7 +623,7 @@ convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
if (!protect_algo && !!strcmp (string, "IDEA"))
protect_algo = GCRY_CIPHER_IDEA;
xfree (string);
value = gcry_sexp_nth_data (list, 3, &valuelen);
if (!value || !valuelen || valuelen > sizeof iv)
goto bad_seckey;
@ -817,7 +846,7 @@ convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
bad_seckey:
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
outofmem:
err = gpg_error (GPG_ERR_ENOMEM);
goto leave;
@ -843,13 +872,13 @@ key_from_sexp (gcry_sexp_t sexp, const char *elems, gcry_mpi_t *array)
}
array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l2);
if (!array[idx])
if (!array[idx])
{
err = gpg_error (GPG_ERR_INV_OBJ); /* Required parameter invalid. */
goto leave;
}
}
leave:
if (err)
{
@ -997,7 +1026,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
gcry_sexp_release (list);
return gpg_error (GPG_ERR_INV_OBJ); /* Invalid structure of object. */
}
algo = gcry_pk_map_name (name);
xfree (name);
@ -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,10 +1067,10 @@ 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);
init_membuf (&mbuf, 50);
put_membuf_str (&mbuf, "(skey");
for (i=j=0; i < npkey; i++)
@ -1073,7 +1103,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
" %S\n"
" (protection sha1 aes %b 1:3 sha1 %b %s))\n",
algoname,
tmpkey,
tmpkey,
(int)sizeof protect_iv, protect_iv,
(int)sizeof salt, salt,
countbuf);
@ -1085,7 +1115,6 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
for (i=0; i < DIM (array); i++)
gcry_mpi_release (array[i]);
return err;
}

View File

@ -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";

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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 }
};
@ -82,14 +85,14 @@ calibrate_get_time (struct calibrate_time_s *data)
#ifdef HAVE_W32_SYSTEM
# ifdef HAVE_W32CE_SYSTEM
GetThreadTimes (GetCurrentThread (),
# else
# else
GetProcessTimes (GetCurrentProcess (),
# endif
&data->creation_time, &data->exit_time,
&data->kernel_time, &data->user_time);
#else
struct tms tmp;
times (&tmp);
data->ticks = tmp.tms_utime;
#endif
@ -100,12 +103,12 @@ static unsigned long
calibrate_elapsed_time (struct calibrate_time_s *starttime)
{
struct calibrate_time_s stoptime;
calibrate_get_time (&stoptime);
#ifdef HAVE_W32_SYSTEM
{
unsigned long long t1, t2;
t1 = (((unsigned long long)starttime->kernel_time.dwHighDateTime << 32)
+ starttime->kernel_time.dwLowDateTime);
t1 += (((unsigned long long)starttime->user_time.dwHighDateTime << 32)
@ -142,7 +145,7 @@ calibrate_s2k_count_one (unsigned long count)
/* Measure the time we need to do the hash operations and deduce an
S2K count which requires about 100ms of time. */
S2K count which requires about 100ms of time. */
static unsigned long
calibrate_s2k_count (void)
{
@ -194,7 +197,7 @@ get_standard_s2k_count (void)
/* Calculate the MIC for a private key or shared secret S-expression.
SHA1HASH should point to a 20 byte buffer. This function is
suitable for all algorithms. */
static int
static int
calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash)
{
const unsigned char *hash_begin, *hash_end;
@ -208,13 +211,13 @@ calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash)
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
if (smatch (&s, n, "private-key"))
is_shared_secret = 0;
else if (smatch (&s, n, "shared-secret"))
is_shared_secret = 1;
else
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
if (*s != '(')
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
hash_begin = s;
@ -223,7 +226,7 @@ calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash)
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
s += n; /* Skip the algorithm name. */
}
@ -232,18 +235,18 @@ calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash)
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
s += n;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
s += n;
if ( *s != ')' )
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
s++;
}
if (*s != ')')
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
s++;
hash_end = s;
@ -266,7 +269,7 @@ calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash)
(d #046129F..[some bytes not shown]..81#)
(p #00e861b..[some bytes not shown]..f1#)
(q #00f7a7c..[some bytes not shown]..61#)
(u #304559a..[some bytes not shown]..9b#)
(u #304559a..[some bytes not shown]..9b#)
the returned block is the S-Expression:
@ -274,7 +277,7 @@ calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash)
*/
static int
do_encryption (const unsigned char *protbegin, size_t protlen,
do_encryption (const unsigned char *protbegin, size_t protlen,
const char *passphrase, const unsigned char *sha1hash,
unsigned char **result, size_t *resultlen)
{
@ -327,14 +330,14 @@ do_encryption (const unsigned char *protbegin, size_t protlen,
{
unsigned char *key;
size_t keylen = PROT_CIPHER_KEYLEN;
key = gcry_malloc_secure (keylen);
if (!key)
rc = out_of_core ();
else
{
rc = hash_passphrase (passphrase, GCRY_MD_SHA1,
3, iv+2*blklen,
3, iv+2*blklen,
get_standard_s2k_count (), key, keylen);
if (!rc)
rc = gcry_cipher_setkey (hd, key, keylen);
@ -354,7 +357,7 @@ do_encryption (const unsigned char *protbegin, size_t protlen,
p += 20;
*p++ = ')';
*p++ = ')';
memcpy (p, iv+blklen, blklen);
memcpy (p, iv+blklen, blklen);
p += blklen;
assert ( p - outbuf == outlen);
rc = gcry_cipher_encrypt (hd, outbuf, enclen, NULL, 0);
@ -372,7 +375,7 @@ do_encryption (const unsigned char *protbegin, size_t protlen,
(protected openpgp-s2k3-sha1-aes-cbc
((sha1 salt no_of_iterations) 16byte_iv)
encrypted_octet_string)
in canoncical format of course. We use asprintf and %n modifier
and dummy values as placeholders. */
{
@ -382,7 +385,7 @@ do_encryption (const unsigned char *protbegin, size_t protlen,
p = xtryasprintf
("(9:protected%d:%s((4:sha18:%n_8bytes_%u:%s)%d:%n%*s)%d:%n%*s)",
(int)strlen (modestr), modestr,
&saltpos,
&saltpos,
(unsigned int)strlen (countbuf), countbuf,
blklen, &ivpos, blklen, "",
enclen, &encpos, enclen, "");
@ -408,7 +411,7 @@ do_encryption (const unsigned char *protbegin, size_t protlen,
/* Protect the key encoded in canonical format in PLAINKEY. We assume
a valid S-Exp here. */
int
int
agent_protect (const unsigned char *plainkey, const char *passphrase,
unsigned char **result, size_t *resultlen)
{
@ -439,9 +442,9 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
if (!smatch (&s, n, "private-key"))
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
if (*s != '(')
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
depth++;
@ -449,13 +452,13 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
for (infidx=0; protect_info[infidx].algo
&& !smatch (&s, n, protect_info[infidx].algo); infidx++)
;
if (!protect_info[infidx].algo)
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
prot_begin = prot_end = NULL;
for (i=0; (c=protect_info[infidx].parmlist[i]); i++)
@ -468,27 +471,27 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
if (n != 1 || c != *s)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
s += n;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
s +=n; /* skip value */
if (*s != ')')
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
depth--;
if (i == protect_info[infidx].prot_to)
prot_end = s;
s++;
}
if (*s != ')' || !prot_begin || !prot_end )
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
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)
@ -496,10 +499,10 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
assert (!depth);
real_end = s-1;
/* Hash the stuff. Because the timestamp_exp won't get protected,
we can't simply hash a continuous buffer but need to use several
md_writes. */
md_writes. */
rc = gcry_md_open (&md, GCRY_MD_SHA1, 0 );
if (rc)
return rc;
@ -552,8 +555,8 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
/* Do the actual decryption and check the return list for consistency. */
static int
do_decryption (const unsigned char *protected, size_t protectedlen,
const char *passphrase,
do_decryption (const unsigned char *protected, size_t protectedlen,
const char *passphrase,
const unsigned char *s2ksalt, unsigned long s2kcount,
const unsigned char *iv, size_t ivlen,
unsigned char **result)
@ -582,7 +585,7 @@ do_decryption (const unsigned char *protected, size_t protectedlen,
{
unsigned char *key;
size_t keylen = PROT_CIPHER_KEYLEN;
key = gcry_malloc_secure (keylen);
if (!key)
rc = out_of_core ();
@ -630,7 +633,7 @@ do_decryption (const unsigned char *protected, size_t protectedlen,
calculation but then be removed. */
static int
merge_lists (const unsigned char *protectedkey,
size_t replacepos,
size_t replacepos,
const unsigned char *cleartext,
unsigned char *sha1hash,
unsigned char **result, size_t *resultlen,
@ -641,7 +644,7 @@ merge_lists (const unsigned char *protectedkey,
const unsigned char *s;
const unsigned char *startpos, *endpos;
int i, rc;
*result = NULL;
*resultlen = 0;
*cutoff = 0;
@ -704,7 +707,7 @@ merge_lists (const unsigned char *protectedkey,
goto invalid_sexp;
n = snext (&s);
if (!smatch (&s, n, "sha1"))
goto invalid_sexp;
goto invalid_sexp;
n = snext (&s);
if (n != 20)
goto invalid_sexp;
@ -717,7 +720,7 @@ merge_lists (const unsigned char *protectedkey,
/* append the parameter list */
memcpy (p, startpos, endpos - startpos);
p += endpos - startpos;
/* Skip over the protected list element in the original list. */
s = protectedkey + replacepos;
assert (*s == '(');
@ -755,7 +758,7 @@ merge_lists (const unsigned char *protectedkey,
*cutoff = p - newlist;
memcpy (p, startpos, endpos - startpos);
p += endpos - startpos;
/* ready */
*result = newlist;
@ -778,14 +781,14 @@ merge_lists (const unsigned char *protectedkey,
/* Unprotect the key encoded in canonical format. We assume a valid
S-Exp here. If a protected-at item is available, its value will
be stored at protocted_at unless this is NULL. */
int
int
agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
gnupg_isotime_t protected_at,
gnupg_isotime_t protected_at,
unsigned char **result, size_t *resultlen)
{
int rc;
const unsigned char *s;
const unsigned char *protect_list;
const unsigned char *protect_list;
size_t n;
int infidx, i;
unsigned char sha1hash[20], sha1hash2[20];
@ -807,21 +810,21 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
if (!smatch (&s, n, "protected-private-key"))
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
if (*s != '(')
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
for (infidx=0; protect_info[infidx].algo
&& !smatch (&s, n, protect_info[infidx].algo); infidx++)
;
if (!protect_info[infidx].algo)
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
/* See wether we have a protected-at timestamp. */
@ -856,7 +859,7 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
/* Now find the list with the protected information. Here is an
example for such a list:
(protected openpgp-s2k3-sha1-aes-cbc
(protected openpgp-s2k3-sha1-aes-cbc
((sha1 <salt> <count>) <Initialization_Vector>)
<encrypted_data>)
*/
@ -869,7 +872,7 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
if (smatch (&s, n, "protected"))
break;
s += n;
@ -881,7 +884,7 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
/* found */
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
if (!smatch (&s, n, "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc"))
return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
if (*s != '(' || s[1] != '(')
@ -889,7 +892,7 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
s += 2;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
if (!smatch (&s, n, "sha1"))
return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
n = snext (&s);
@ -905,7 +908,7 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
is nothing we should worry about */
if (s[n] != ')' )
return gpg_error (GPG_ERR_INV_SEXP);
/* Old versions of gpg-agent used the funny floating point number in
a byte encoding as specified by OpenPGP. However this is not
needed and thus we now store it as a plain unsigned integer. We
@ -935,8 +938,8 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
cleartext = NULL; /* Avoid cc warning. */
rc = do_decryption (s, n,
passphrase, s2ksalt, s2kcount,
@ -1011,7 +1014,7 @@ agent_private_key_type (const unsigned char *privatekey)
store this key in the caller provided buffer KEY. The caller must
provide an HASHALGO, a valid S2KMODE (see rfc-2440) and depending on
that mode an S2KSALT of 8 random bytes and an S2KCOUNT.
Returns an error code on failure. */
static int
hash_passphrase (const char *passphrase, int hashalgo,
@ -1031,7 +1034,7 @@ hash_passphrase (const char *passphrase, int hashalgo,
return gpg_error (GPG_ERR_INV_VALUE);
if ((s2kmode == 1 ||s2kmode == 3) && !s2ksalt)
return gpg_error (GPG_ERR_INV_VALUE);
rc = gcry_md_open (&md, hashalgo, GCRY_MD_FLAG_SECURE);
if (rc)
return rc;
@ -1065,7 +1068,7 @@ hash_passphrase (const char *passphrase, int hashalgo,
}
if (count < 8)
gcry_md_write (md, s2ksalt, count);
else
else
{
gcry_md_write (md, s2ksalt, 8);
count -= 8;
@ -1074,7 +1077,7 @@ hash_passphrase (const char *passphrase, int hashalgo,
}
else
gcry_md_write (md, passphrase, pwlen);
gcry_md_final (md);
i = gcry_md_get_algo_dlen (hashalgo);
if (i > keylen - used)
@ -1094,7 +1097,7 @@ s2k_hash_passphrase (const char *passphrase, int hashalgo,
unsigned int s2kcount,
unsigned char *key, size_t keylen)
{
return hash_passphrase (passphrase, hashalgo, s2kmode, s2ksalt,
return hash_passphrase (passphrase, hashalgo, s2kmode, s2ksalt,
(16ul + (s2kcount & 15)) << ((s2kcount >> 4) + 6),
key, keylen);
}
@ -1137,7 +1140,7 @@ make_shadow_info (const char *serialno, const char *idstring)
S-expression is returned in an allocated buffer RESULT will point
to. The input parameters are expected to be valid canonicalized
S-expressions */
int
int
agent_shadow_key (const unsigned char *pubkey,
const unsigned char *shadow_info,
unsigned char **result)
@ -1159,16 +1162,16 @@ agent_shadow_key (const unsigned char *pubkey,
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
if (!smatch (&s, n, "public-key"))
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
if (*s != '(')
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
depth++;
s++;
n = snext (&s);
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
s += n; /* skip over the algorithm name */
while (*s != ')')
@ -1178,15 +1181,15 @@ agent_shadow_key (const unsigned char *pubkey,
depth++;
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
s += n;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
s +=n; /* skip value */
if (*s != ')')
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
depth--;
s++;
}
@ -1218,7 +1221,7 @@ agent_shadow_key (const unsigned char *pubkey,
/* Parse a canonical encoded shadowed key and return a pointer to the
inner list with the shadow_info */
int
int
agent_get_shadow_info (const unsigned char *shadowkey,
unsigned char const **shadow_info)
{
@ -1233,16 +1236,16 @@ agent_get_shadow_info (const unsigned char *shadowkey,
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
if (!smatch (&s, n, "shadowed-private-key"))
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
if (*s != '(')
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
depth++;
s++;
n = snext (&s);
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
s += n; /* skip over the algorithm name */
for (;;)
@ -1254,24 +1257,24 @@ agent_get_shadow_info (const unsigned char *shadowkey,
depth++;
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
if (smatch (&s, n, "shadowed"))
break;
s += n;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
s +=n; /* skip value */
if (*s != ')')
return gpg_error (GPG_ERR_INV_SEXP);
return gpg_error (GPG_ERR_INV_SEXP);
depth--;
s++;
}
/* Found the shadowed list, S points to the protocol */
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
if (smatch (&s, n, "t1-v1"))
{
if (*s != '(')
@ -1291,7 +1294,7 @@ agent_get_shadow_info (const unsigned char *shadowkey,
parameters addresses. If the serial number or the ID string is not
required, NULL may be passed for them. */
gpg_error_t
parse_shadow_info (const unsigned char *shadow_info,
parse_shadow_info (const unsigned char *shadow_info,
char **r_hexsn, char **r_idstr)
{
const unsigned char *s;
@ -1328,7 +1331,7 @@ parse_shadow_info (const unsigned char *shadow_info,
}
return gpg_error (GPG_ERR_INV_SEXP);
}
if (r_idstr)
{
*r_idstr = xtrymalloc (n+1);
@ -1347,4 +1350,3 @@ parse_shadow_info (const unsigned char *shadow_info,
return 0;
}

View File

@ -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.

View File

@ -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)

View File

@ -106,14 +106,14 @@ do_bin2hex (const void *buffer, size_t length, char *stringbuf, int with_colon)
{
const unsigned char *s;
char *p;
if (!stringbuf)
{
/* Not really correct for with_colon but we don't care about the
one wasted byte. */
size_t n = with_colon? 3:2;
size_t nbytes = n * length + 1;
if (length && (nbytes-1) / n != length)
size_t n = with_colon? 3:2;
size_t nbytes = n * length + 1;
if (length && (nbytes-1) / n != length)
{
gpg_err_set_errno (ENOMEM);
return NULL;
@ -122,7 +122,7 @@ do_bin2hex (const void *buffer, size_t length, char *stringbuf, int with_colon)
if (!stringbuf)
return NULL;
}
for (s = buffer, p = stringbuf; length; length--, s++)
{
if (with_colon && s != buffer)
@ -171,7 +171,7 @@ bin2hexcolon (const void *buffer, size_t length, char *stringbuf)
buffer, the function returns NULL and won't change the existing
conent of buffer. In-place conversion is possible as long as
BUFFER points to HEXSTRING.
If BUFFER is NULL and bufsize is 0 the function scans HEXSTRING but
does not store anything. This may be used to find the end of
hexstring.
@ -204,7 +204,7 @@ hex2str (const char *hexstring, char *buffer, size_t bufsize, size_t *buflen)
{
if (count > bufsize)
return NULL; /* Too long. */
for (s=hexstring, idx=0; hexdigitp (s) && hexdigitp (s+1); s += 2)
((unsigned char*)buffer)[idx++] = xtoi_2 (s);
if (need_nul)
@ -244,6 +244,3 @@ hex2str_alloc (const char *hexstring, size_t *r_count)
BUG ();
return result;
}

227
common/openpgp-oid.c Normal file
View 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
View 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;
}

View File

@ -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. */
@ -75,10 +81,10 @@
/* GCC attributes. */
#if __GNUC__ >= 4
#if __GNUC__ >= 4
# define GNUPG_GCC_A_SENTINEL(a) __attribute__ ((sentinel(a)))
#else
# define GNUPG_GCC_A_SENTINEL(a)
# define GNUPG_GCC_A_SENTINEL(a)
#endif
@ -132,14 +138,14 @@ int answer_is_yes_no_quit (const char *s);
int answer_is_okay_cancel (const char *s, int def_answer);
/*-- xreadline.c --*/
ssize_t read_line (FILE *fp,
ssize_t read_line (FILE *fp,
char **addr_of_buffer, size_t *length_of_buffer,
size_t *max_length);
/*-- b64enc.c and b64dec.c --*/
struct b64state
{
struct b64state
{
unsigned int flags;
int idx;
int quad_count;
@ -184,9 +190,9 @@ unsigned char *make_canon_sexp_from_rsa_pk (const void *m, size_t mlen,
size_t *r_len);
gpg_error_t get_rsa_pk_from_canon_sexp (const unsigned char *keydata,
size_t keydatalen,
unsigned char const **r_n,
unsigned char const **r_n,
size_t *r_nlen,
unsigned char const **r_e,
unsigned char const **r_e,
size_t *r_elen);
gpg_error_t get_pk_algo_from_canon_sexp (const unsigned char *keydata,
size_t keydatalen,
@ -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);
@ -226,7 +237,7 @@ const char *dirmngr_socket_name (void);
gpgconf. */
#define GNUPG_MODULE_NAME_AGENT 1
#define GNUPG_MODULE_NAME_PINENTRY 2
#define GNUPG_MODULE_NAME_SCDAEMON 3
#define GNUPG_MODULE_NAME_SCDAEMON 3
#define GNUPG_MODULE_NAME_DIRMNGR 4
#define GNUPG_MODULE_NAME_PROTECT_TOOL 5
#define GNUPG_MODULE_NAME_CHECK_PATTERN 6
@ -281,7 +292,7 @@ int gnupg_compare_version (const char *a, const char *b);
#ifndef HAVE_TTYNAME
/* Systems without ttyname (W32) will merely return NULL. */
static inline char *
ttyname (int fd)
ttyname (int fd)
{
(void)fd;
return NULL;

View File

@ -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])
#

View File

@ -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)

View File

@ -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.

View File

@ -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 \
@ -110,7 +111,7 @@ gpg2_SOURCES = gpg.c \
gpgv2_SOURCES = gpgv.c \
$(common_source) \
verify.c
verify.c
#gpgd_SOURCES = gpgd.c \
# ks-proto.h \

View File

@ -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;
p = gcry_mpi_get_opaque ( a, &n );
iobuf_write (out, p, (n+7)/8 );
}
unsigned int n;
void *p;
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 )
{
@ -272,36 +282,39 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
ndays = 0;
write_16(a, ndays);
}
iobuf_put (a, pk->pubkey_algo );
/* Get number of secret and public parameters. They are held in one
array first the public ones, then the secret ones. */
nskey = pubkey_get_nskey (pk->pubkey_algo);
npkey = pubkey_get_npkey (pk->pubkey_algo);
/* If we don't have any public parameters - which is the case if we
don't know the algorithm used - the parameters are stored as one
blob in a faked (opaque) MPI. */
if (!npkey)
if (!npkey)
{
write_fake_data (a, pk->pkey[0]);
goto leave;
}
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)
{
/* This is a secret key packet. */
struct seckey_info *ski = pk->seckey_info;
/* Build the header for protected (encrypted) secret parameters. */
if (ski->is_protected)
if (ski->is_protected)
{
if ( is_RSA (pk->pubkey_algo) && pk->version < 4 && !ski->s2k.mode )
{
@ -321,12 +334,12 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
viewed as a private/experimental extension (this
is not specified in rfc2440 but the same scheme
is used for all other algorithm identifiers). */
iobuf_put (a, 101);
iobuf_put (a, 101);
iobuf_put (a, ski->s2k.hash_algo);
iobuf_write (a, "GNU", 3 );
iobuf_put (a, ski->s2k.mode - 1000);
}
else
else
{
iobuf_put (a, ski->s2k.mode);
iobuf_put (a, ski->s2k.hash_algo);
@ -336,7 +349,7 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
iobuf_write (a, ski->s2k.salt, 8);
if (ski->s2k.mode == 3)
iobuf_put (a, ski->s2k.count);
iobuf_put (a, ski->s2k.count);
/* For our special modes 1001, 1002 we do not need an IV. */
if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002)
@ -347,10 +360,10 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
iobuf_put (a, 0 );
if (ski->s2k.mode == 1001)
; /* GnuPG extension - don't write a secret key at all. */
; /* GnuPG extension - don't write a secret key at all. */
else if (ski->s2k.mode == 1002)
{
/* GnuPG extension - divert to OpenPGP smartcard. */
{
/* GnuPG extension - divert to OpenPGP smartcard. */
/* Length of the serial number or 0 for no serial number. */
iobuf_put (a, ski->ivlen );
/* The serial number gets stored in the IV field. */
@ -361,19 +374,19 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
/* The secret key is protected - write it out as it is. */
byte *p;
unsigned int ndatabits;
assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE));
p = gcry_mpi_get_opaque (pk->pkey[npkey], &ndatabits);
iobuf_write (a, p, (ndatabits+7)/8 );
}
else if (ski->is_protected)
else if (ski->is_protected)
{
/* The secret key is protected the old v4 way. */
for ( ; i < nskey; i++ )
for ( ; i < nskey; i++ )
{
byte *p;
unsigned int ndatabits;
assert (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE));
p = gcry_mpi_get_opaque (pk->pkey[i], &ndatabits);
iobuf_write (a, p, (ndatabits+7)/8);
@ -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 );
}
@ -442,9 +455,9 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
int rc = 0;
int n, i;
IOBUF a = iobuf_temp();
write_version( a, ctb );
if ( enc->throw_keyid )
if ( enc->throw_keyid )
{
write_32(a, 0 ); /* Don't tell Eve who can decrypt the message. */
write_32(a, 0 );
@ -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;
@ -498,7 +512,7 @@ do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt )
for(i=0; i < pt->namelen; i++ )
iobuf_put(out, pt->name[i] );
rc = write_32(out, pt->timestamp );
if (rc)
if (rc)
return rc;
n = 0;
@ -614,7 +628,7 @@ delete_sig_subpkt (subpktarea_t *area, sigsubpkttype_t reqtype )
}
if( buflen < n )
break;
type = *buffer & 0x7f;
if( type == reqtype ) {
buffer++;
@ -648,7 +662,7 @@ delete_sig_subpkt (subpktarea_t *area, sigsubpkttype_t reqtype )
* Note: All pointers into sig->[un]hashed (e.g. returned by
* parse_sig_subpkt) are not valid after a call to this function. The
* data to put into the subpaket should be in a buffer with a length
* of buflen.
* of buflen.
*/
void
build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
@ -751,7 +765,7 @@ build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
case SIGSUBPKT_SIGNATURE:
hashed = 0;
break;
default:
default:
hashed = 1;
break;
}
@ -802,7 +816,7 @@ build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
memcpy (p, buffer, buflen);
}
if (hashed)
if (hashed)
sig->hashed = newarea;
else
sig->unhashed = newarea;
@ -1088,7 +1102,7 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
if ( sig->version < 4 )
iobuf_put (a, 5 ); /* Constant */
iobuf_put (a, sig->sig_class );
if ( sig->version < 4 )
if ( sig->version < 4 )
{
write_32(a, sig->timestamp );
write_32(a, sig->keyid[0] );
@ -1096,7 +1110,7 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
}
iobuf_put(a, sig->pubkey_algo );
iobuf_put(a, sig->digest_algo );
if ( sig->version >= 4 )
if ( sig->version >= 4 )
{
size_t nn;
/* Timestamp and keyid must have been packed into the subpackets
@ -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)
{

View File

@ -1751,7 +1751,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
membuf_t data;
size_t n, len;
char *p, *buf, *endp;
if (!keygrip || strlen(keygrip) != 40 || !s_ciphertext || !r_buf || !r_buflen)
return gpg_error (GPG_ERR_INV_VALUE);
*r_buf = NULL;

454
g10/ecdh.c Normal file
View 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);
}

View File

@ -84,7 +84,7 @@ encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey)
/* The encrypted session key is prefixed with a one-octet algorithm id. */
buf[0] = (*seskey)->algo;
memcpy( buf + 1, (*seskey)->key, (*seskey)->keylen );
/* We only pass already checked values to the following fucntion,
thus we consider any failure as fatal. */
if (openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1))
@ -119,7 +119,7 @@ use_mdc(PK_LIST pk_list,int algo)
if(select_mdc_from_pklist(pk_list))
return 1;
/* The keys don't support MDC, so now we do a bit of a hack - if any
of the AESes or TWOFISH are in the prefs, we assume that the user
can handle a MDC. This is valid for PGP 7, which can handle MDCs
@ -181,7 +181,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
memset( &zfx, 0, sizeof zfx);
memset( &tfx, 0, sizeof tfx);
init_packet(&pkt);
/* Prepare iobufs. */
inp = iobuf_open(filename);
if (inp)
@ -200,23 +200,23 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
release_progress_context (pfx);
return rc;
}
handle_progress (pfx, inp, filename);
if (opt.textmode)
iobuf_push_filter( inp, text_filter, &tfx );
/* Due the the fact that we use don't use an IV to encrypt the
session key we can't use the new mode with RFC1991 because it has
no S2K salt. RFC1991 always uses simple S2K. */
if ( RFC1991 && use_seskey )
use_seskey = 0;
cfx.dek = NULL;
if ( mode )
if ( mode )
{
int canceled;
s2k = xmalloc_clear( sizeof *s2k );
s2k->mode = RFC1991? 0:opt.s2k_mode;
s2k->hash_algo = S2K_DIGEST_ALGO;
@ -233,37 +233,37 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
release_progress_context (pfx);
return rc;
}
if (use_seskey && s2k->mode != 1 && s2k->mode != 3)
if (use_seskey && s2k->mode != 1 && s2k->mode != 3)
{
use_seskey = 0;
log_info (_("can't use a symmetric ESK packet "
"due to the S2K mode\n"));
}
if ( use_seskey )
{
DEK *dek = NULL;
seskeylen = openpgp_cipher_get_algo_keylen (default_cipher_algo ());
encrypt_seskey( cfx.dek, &dek, enckey );
xfree( cfx.dek ); cfx.dek = dek;
}
if (opt.verbose)
log_info(_("using cipher %s\n"),
openpgp_cipher_algo_name (cfx.dek->algo));
cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo);
}
if (do_compress && cfx.dek && cfx.dek->use_mdc
&& is_file_compressed(filename, &rc))
{
if (opt.verbose)
log_info(_("`%s' already compressed\n"), filename);
do_compress = 0;
do_compress = 0;
}
if ( rc || (rc = open_outfile (-1, filename, opt.armor? 1:0, &out )))
{
iobuf_cancel (inp);
@ -272,7 +272,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
release_progress_context (pfx);
return rc;
}
if ( opt.armor )
{
afx = new_armor_context ();
@ -296,7 +296,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
log_error("build symkey packet failed: %s\n", g10_errstr(rc) );
xfree (enc);
}
if (!opt.no_literal)
pt = setup_plaintext_name (filename, inp);
@ -347,7 +347,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
pkt.pkttype = 0;
pkt.pkt.generic = NULL;
}
/* Register the cipher filter. */
if (mode)
iobuf_push_filter ( out, cipher_filter, &cfx );
@ -359,14 +359,14 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
zfx.new_ctb = 1;
push_compress_filter (out, &zfx, default_compress_algo());
}
/* Do the work. */
if (!opt.no_literal)
{
if ( (rc = build_packet( out, &pkt )) )
log_error("build_packet failed: %s\n", g10_errstr(rc) );
}
else
else
{
/* User requested not to create a literal packet, so we copy the
plain data. */
@ -380,12 +380,12 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
}
wipememory (copy_buffer, 4096); /* burn buffer */
}
/* Finish the stuff. */
iobuf_close (inp);
if (rc)
iobuf_cancel(out);
else
else
{
iobuf_close (out); /* fixme: check returncode */
if (mode)
@ -425,7 +425,7 @@ setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek)
static int
write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek,
write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek,
iobuf_t out)
{
int rc, seskeylen = openpgp_cipher_get_algo_keylen (dek->algo);
@ -492,7 +492,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
memset( &tfx, 0, sizeof tfx);
init_packet(&pkt);
if (use_symkey
if (use_symkey
&& (rc=setup_symkey(&symkey_s2k,&symkey_dek)))
{
release_progress_context (pfx);
@ -509,7 +509,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
return rc;
}
}
if(PGP2)
{
for (work_list=pk_list; work_list; work_list=work_list->next)
@ -560,17 +560,17 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
rc = open_outfile (outputfd, filename, opt.armor? 1:0, &out);
if (rc)
goto leave;
if (opt.armor)
{
afx = new_armor_context ();
push_armor_filter (afx, out);
}
/* Create a session key. */
cfx.dek = xmalloc_secure_clear (sizeof *cfx.dek);
if (!opt.def_cipher_algo)
{
{
/* Try to get it from the prefs. */
cfx.dek->algo = select_algo_from_prefs (pk_list, PREFTYPE_SYM, -1, NULL);
/* The only way select_algo_from_prefs can fail here is when
@ -582,7 +582,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
if (cfx.dek->algo == -1)
{
cfx.dek->algo = CIPHER_ALGO_3DES;
if (PGP2)
{
log_info(_("unable to use the IDEA cipher for all of the keys "
@ -610,12 +610,12 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
openpgp_cipher_algo_name (opt.def_cipher_algo),
opt.def_cipher_algo);
}
cfx.dek->algo = opt.def_cipher_algo;
}
cfx.dek->use_mdc = use_mdc (pk_list,cfx.dek->algo);
/* Only do the is-file-already-compressed check if we are using a
MDC. This forces compressed files to be re-compressed if we do
not have a MDC to give some protection against chosen ciphertext
@ -625,7 +625,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
{
if (opt.verbose)
log_info(_("`%s' already compressed\n"), filename);
do_compress = 0;
do_compress = 0;
}
if (rc2)
{
@ -636,7 +636,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
make_session_key (cfx.dek);
if (DBG_CIPHER)
log_printhex ("DEK is: ", cfx.dek->key, cfx.dek->keylen );
rc = write_pubkey_enc_from_list (pk_list, cfx.dek, out);
if (rc)
goto leave;
@ -647,16 +647,16 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
secret key needed to decrypt. */
if(use_symkey && (rc = write_symkey_enc(symkey_s2k,symkey_dek,cfx.dek,out)))
goto leave;
if (!opt.no_literal)
pt = setup_plaintext_name (filename, inp);
if (filefd != -1
&& !iobuf_is_pipe_filename (filename) && *filename && !opt.textmode )
{
off_t tmpsize;
int overflow;
if ( !(tmpsize = iobuf_get_filelength(inp, &overflow))
&& !overflow && opt.verbose)
log_info(_("WARNING: `%s' is an empty file\n"), filename );
@ -672,7 +672,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
else
filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
if (!opt.no_literal)
if (!opt.no_literal)
{
pt->timestamp = make_timestamp();
pt->mode = opt.textmode ? 't' : 'b';
@ -693,7 +693,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
if (do_compress)
{
int compr_algo = opt.compress_algo;
if (compr_algo == -1)
{
compr_algo = select_algo_from_prefs (pk_list, PREFTYPE_ZIP, -1, NULL);
@ -702,7 +702,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
/* Theoretically impossible to get here since uncompressed
is implicit. */
}
else if (!opt.expert
else if (!opt.expert
&& select_algo_from_prefs(pk_list, PREFTYPE_ZIP,
compr_algo, NULL) != compr_algo)
{
@ -710,7 +710,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
" violates recipient preferences\n"),
compress_algo_to_string(compr_algo), compr_algo);
}
/* Algo 0 means no compression. */
if (compr_algo)
{
@ -719,7 +719,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
push_compress_filter (out,&zfx,compr_algo);
}
}
/* Do the work. */
if (!opt.no_literal)
{
@ -750,7 +750,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
iobuf_close (inp);
if (rc)
iobuf_cancel (out);
else
else
{
iobuf_close (out); /* fixme: check returncode */
write_status (STATUS_END_ENCRYPTION);
@ -779,7 +779,7 @@ encrypt_filter (void *opaque, int control,
size_t size = *ret_len;
encrypt_filter_context_t *efx = opaque;
int rc = 0;
if (control == IOBUFCTRL_UNDERFLOW) /* decrypt */
{
BUG(); /* not used */
@ -789,19 +789,19 @@ encrypt_filter (void *opaque, int control,
if ( !efx->header_okay )
{
efx->cfx.dek = xmalloc_secure_clear ( sizeof *efx->cfx.dek );
if ( !opt.def_cipher_algo )
if ( !opt.def_cipher_algo )
{
/* Try to get it from the prefs. */
efx->cfx.dek->algo =
select_algo_from_prefs (efx->pk_list, PREFTYPE_SYM, -1, NULL);
if (efx->cfx.dek->algo == -1 )
if (efx->cfx.dek->algo == -1 )
{
/* Because 3DES is implicitly in the prefs, this can
only happen if we do not have any public keys in
the list. */
efx->cfx.dek->algo = DEFAULT_CIPHER_ALGO;
}
/* In case 3DES has been selected, print a warning if
any key does not have a preference for AES. This
should help to indentify why encrypting to several
@ -810,7 +810,7 @@ encrypt_filter (void *opaque, int control,
&& efx->cfx.dek->algo == CIPHER_ALGO_3DES)
warn_missing_aes_from_pklist (efx->pk_list);
}
else
else
{
if (!opt.expert
&& select_algo_from_prefs (efx->pk_list,PREFTYPE_SYM,
@ -820,12 +820,12 @@ encrypt_filter (void *opaque, int control,
"violates recipient preferences\n"),
openpgp_cipher_algo_name (opt.def_cipher_algo),
opt.def_cipher_algo);
efx->cfx.dek->algo = opt.def_cipher_algo;
}
efx->cfx.dek->use_mdc = use_mdc (efx->pk_list,efx->cfx.dek->algo);
make_session_key ( efx->cfx.dek );
if (DBG_CIPHER)
log_printhex ("DEK is: ", efx->cfx.dek->key, efx->cfx.dek->keylen);
@ -841,13 +841,13 @@ encrypt_filter (void *opaque, int control,
if(rc)
return rc;
}
iobuf_push_filter (a, cipher_filter, &efx->cfx);
efx->header_okay = 1;
}
rc = iobuf_write (a, buf, size);
}
else if (control == IOBUFCTRL_FREE)
{
@ -876,9 +876,9 @@ write_pubkey_enc_from_list (PK_LIST pk_list, DEK *dek, iobuf_t out)
for ( ; pk_list; pk_list = pk_list->next )
{
gcry_mpi_t frame;
pk = pk_list->pk;
print_pubkey_algo_note ( pk->pubkey_algo );
enc = xmalloc_clear ( sizeof *enc );
enc->pubkey_algo = pk->pubkey_algo;
@ -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);
@ -927,7 +927,7 @@ write_pubkey_enc_from_list (PK_LIST pk_list, DEK *dek, iobuf_t out)
pkt.pkt.pubkey_enc = enc;
rc = build_packet (out, &pkt);
if (rc)
log_error ("build_packet(pubkey_enc) failed: %s\n",
log_error ("build_packet(pubkey_enc) failed: %s\n",
g10_errstr (rc));
}
free_pubkey_enc(enc);
@ -946,9 +946,9 @@ encrypt_crypt_files (ctrl_t ctrl, int nfiles, char **files, strlist_t remusr)
if (opt.outfile)
{
log_error(_("--output doesn't work for this command\n"));
return;
return;
}
if (!nfiles)
{
char line[2048];

View File

@ -107,7 +107,7 @@ export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users,
kbnode_t *keyblock_out, unsigned int options )
{
int any, rc;
rc = do_export_stream (ctrl, out, users, 0, keyblock_out, options, &any);
if (!rc && !any)
rc = -1;
@ -197,9 +197,9 @@ do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options )
int any, rc;
armor_filter_context_t *afx = NULL;
compress_filter_context_t zfx;
memset( &zfx, 0, sizeof zfx);
rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, &out );
if (rc)
return rc;
@ -251,7 +251,7 @@ subkey_in_list_p (subkey_list_t list, KBNODE node)
u32 kid[2];
keyid_from_pk (node->pkt->pkt.public_key, kid);
for (; list; list = list->next)
if (list->kid[0] == kid[0] && list->kid[1] == kid[1])
return 1;
@ -293,17 +293,17 @@ exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node)
case KEYDB_SEARCH_MODE_LONG_KID:
keyid_from_pk (node->pkt->pkt.public_key, kid);
break;
case KEYDB_SEARCH_MODE_FPR16:
case KEYDB_SEARCH_MODE_FPR20:
case KEYDB_SEARCH_MODE_FPR:
fingerprint_from_pk (node->pkt->pkt.public_key, fpr,&fprlen);
break;
default:
break;
}
switch(desc->mode)
{
case KEYDB_SEARCH_MODE_SHORT_KID:
@ -346,7 +346,7 @@ canon_pubkey_algo (int algo)
case GCRY_PK_RSA:
case GCRY_PK_RSA_E:
case GCRY_PK_RSA_S: return GCRY_PK_RSA;
case GCRY_PK_ELG:
case GCRY_PK_ELG:
case GCRY_PK_ELG_E: return GCRY_PK_ELG;
default: return algo;
}
@ -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)
@ -415,7 +415,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
goto bad_seckey;
protect_algo = gcry_cipher_map_name (string);
xfree (string);
value = gcry_sexp_nth_data (list, 3, &valuelen);
if (!value || !valuelen || valuelen > sizeof iv)
goto bad_seckey;
@ -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)
{
@ -576,11 +648,17 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
err = openpgp_md_test_algo (s2k_algo);
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);
@ -607,7 +685,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
err = gpg_error_from_syserror ();
goto leave;
}
ski->is_protected = 1;
ski->sha1chk = 1;
ski->algo = protect_algo;
@ -636,7 +714,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
bad_seckey:
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
outofmem:
err = gpg_error (GPG_ERR_ENOMEM);
goto leave;
@ -671,7 +749,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
init_packet (&pkt);
kdbhd = keydb_new ();
if (!users)
if (!users)
{
ndesc = 1;
desc = xcalloc (ndesc, sizeof *desc);
@ -679,10 +757,10 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
}
else
{
for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++)
for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++)
;
desc = xmalloc ( ndesc * sizeof *desc);
for (ndesc=0, sl=users; sl; sl = sl->next)
{
if (!(err=classify_user_id (sl->d, desc+ndesc)))
@ -708,7 +786,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
goto leave;
}
#endif
/* For secret key export we need to setup a decryption context. */
if (secret)
{
@ -721,7 +799,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
log_error ("error getting the KEK: %s\n", gpg_strerror (err));
goto leave;
}
/* Prepare a cipher context. */
err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
GCRY_CIPHER_MODE_AESWRAP, 0);
@ -737,20 +815,20 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
kek = NULL;
}
while (!(err = keydb_search2 (kdbhd, desc, ndesc, &descindex)))
while (!(err = keydb_search2 (kdbhd, desc, ndesc, &descindex)))
{
int skip_until_subkey = 0;
u32 keyid[2];
PKT_public_key *pk;
if (!users)
if (!users)
desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
/* Read the keyblock. */
release_kbnode (keyblock);
keyblock = NULL;
err = keydb_get_keyblock (kdbhd, &keyblock);
if (err)
if (err)
{
log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
goto leave;
@ -802,7 +880,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
clean_key (keyblock, opt.verbose, (options&EXPORT_MINIMAL), NULL, NULL);
/* And write it. */
for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
{
if (skip_until_subkey)
{
@ -835,7 +913,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
subkey and include that subkey into the output
too. Need to add this subkey to a list so that
it won't get processed a second time.
So the first step here is to check that list and
skip in any case if the key is in that list.
@ -843,7 +921,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
function of GnuPG < 2.1 is not able to merge
secret keys and thus it is useless to output them
as two separate keys and have import merge them. */
if (subkey_in_list_p (subkey_list, node))
if (subkey_in_list_p (subkey_list, node))
skip_until_subkey = 1; /* Already processed this one. */
else
{
@ -854,7 +932,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
&& exact_subkey_match_p (desc+j, node))
break;
if (!(j < ndesc))
skip_until_subkey = 1; /* No other one matching. */
skip_until_subkey = 1; /* No other one matching. */
}
}
@ -885,7 +963,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
&& node->pkt->pkt.signature->revkey)
{
int i;
for (i=0;i<node->pkt->pkt.signature->numrevkeys;i++)
if ( (node->pkt->pkt.signature->revkey[i]->class & 0x40))
break;
@ -904,7 +982,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
or a signature on an attrib */
while (kbctx->next && kbctx->next->pkt->pkttype==PKT_SIGNATURE)
kbctx = kbctx->next;
continue;
}
@ -913,7 +991,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
{
u32 subkidbuf[2], *subkid;
char *hexgrip, *serialno;
pk = node->pkt->pkt.public_key;
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
subkid = NULL;
@ -930,7 +1008,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
skip_until_subkey = 1;
continue;
}
err = hexkeygrip_from_pk (pk, &hexgrip);
if (err)
{
@ -970,7 +1048,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
/* Create a key stub. */
struct seckey_info *ski;
const char *s;
pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
if (!ski)
{
@ -989,7 +1067,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
ski->ivlen++, s += 2)
ski->iv[ski->ivlen] = xtoi_2 (s);
}
if ((options&EXPORT_SEXP_FORMAT))
err = build_sexp (out, node->pkt, &indent);
else
@ -1032,7 +1110,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err);
if (!realkeylen)
goto unwraperror; /* Invalid csexp. */
err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen);
xfree (key);
key = NULL;
@ -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"); */
@ -1242,7 +1330,7 @@ build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent)
/* For some packet types we write them in a S-expression format. This
is still EXPERIMENTAL and subject to change. */
static int
static int
build_sexp (iobuf_t out, PACKET *pkt, int *indent)
{
int rc;

View File

@ -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);
}

View File

@ -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);

View File

@ -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.
*
@ -200,7 +200,7 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
rc = import (ctrl, inp2, fname, stats, fpr, fpr_len, options);
iobuf_close(inp2);
/* Must invalidate that ugly cache to actually close it. */
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE,
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE,
0, (char*)fname);
if( rc )
log_error("import from `%s' failed: %s\n", fname,
@ -294,7 +294,7 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats,
if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY )
rc = import_one (ctrl, fname, keyblock,
stats, fpr, fpr_len, options, 0);
else if( keyblock->pkt->pkttype == PKT_SECRET_KEY )
else if( keyblock->pkt->pkttype == PKT_SECRET_KEY )
rc = import_secret_one (ctrl, fname, keyblock, stats, options);
else if( keyblock->pkt->pkttype == PKT_SIGNATURE
&& keyblock->pkt->pkt.signature->sig_class == 0x20 )
@ -647,7 +647,7 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
kbnode_t node;
PKT_public_key *pk;
int problem=0;
merge_keys_and_selfsig(keyblock);
pk=keyblock->pkt->pkt.public_key;
@ -672,9 +672,9 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
{
if (openpgp_cipher_test_algo (prefs->value))
{
const char *algo =
const char *algo =
(openpgp_cipher_test_algo (prefs->value)
? num
? num
: openpgp_cipher_algo_name (prefs->value));
if(!problem)
check_prefs_warning(pk);
@ -689,7 +689,7 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
{
const char *algo =
(gcry_md_test_algo (prefs->value)
? num
? num
: gcry_md_algo_name (prefs->value));
if(!problem)
check_prefs_warning(pk);
@ -801,7 +801,7 @@ import_one (ctrl_t ctrl,
log_error( _("key %s: no user ID\n"), keystr_from_pk(pk));
return 0;
}
if (opt.interactive) {
if(is_status_enabled())
print_import_check (pk, uidnode->pkt->pkt.user_id);
@ -938,7 +938,7 @@ import_one (ctrl_t ctrl,
size_t an;
fingerprint_from_pk (pk_orig, afp, &an);
while (an < MAX_FINGERPRINT_LEN)
while (an < MAX_FINGERPRINT_LEN)
afp[an++] = 0;
rc = keydb_search_fpr (hd, afp);
}
@ -962,7 +962,7 @@ import_one (ctrl_t ctrl,
n_sigs_cleaned = fix_bad_direct_key_sigs (keyblock_orig, keyid);
if (n_sigs_cleaned)
commit_kbnode (&keyblock_orig);
/* and try to merge the block */
clear_kbnode_flags( keyblock_orig );
clear_kbnode_flags( keyblock );
@ -1032,13 +1032,13 @@ import_one (ctrl_t ctrl,
stats->n_sigs_cleaned +=n_sigs_cleaned;
stats->n_uids_cleaned +=n_uids_cleaned;
if (is_status_enabled ())
if (is_status_enabled ())
print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0)));
}
else
{
same_key = 1;
if (is_status_enabled ())
if (is_status_enabled ())
print_import_ok (pk, 0);
if( !opt.quiet )
@ -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));
@ -1228,7 +1350,7 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
if (ski->is_protected)
{
char countbuf[35];
/* Note that the IVLEN may be zero if we are working on a
dummy key. We can't express that in an S-expression and
thus we send dummy data for the IV. */
@ -1289,9 +1411,9 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
transferkey = NULL;
/* Send the wrapped key to the agent. */
{
{
char *desc = gpg_format_keydesc (pk, 1, 1);
err = agent_import_key (ctrl, desc, &cache_nonce,
err = agent_import_key (ctrl, desc, &cache_nonce,
wrappedkey, wrappedkeylen);
xfree (desc);
}
@ -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);
@ -1392,7 +1516,7 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
* with the trust calculation.
*/
static int
import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
struct stats_s *stats, unsigned int options)
{
PKT_public_key *pk;
@ -1400,17 +1524,17 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
KBNODE node, uidnode;
u32 keyid[2];
int rc = 0;
/* Get the key and print some info about it */
node = find_kbnode (keyblock, PKT_SECRET_KEY);
if (!node)
BUG ();
pk = node->pkt->pkt.public_key;
keyid_from_pk (pk, keyid);
uidnode = find_next_kbnode (keyblock, PKT_USER_ID);
if (opt.verbose)
{
log_info ("sec %4u%c/%s %s ",
@ -1423,7 +1547,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
log_printf ("\n");
}
stats->secret_read++;
if (!uidnode)
{
log_error( _("key %s: no user ID\n"), keystr_from_pk (pk));
@ -1456,10 +1580,10 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
log_error (_("importing secret keys not allowed\n"));
return 0;
}
#endif
#endif
clear_kbnode_flags (keyblock);
if (!(options&IMPORT_MERGE_ONLY) || !have_secret_key_with_kid (keyid) )
{
/* We don't have this key, insert as a new key. */
@ -1477,7 +1601,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
/* Fixme: We should check for an invalid keyblock and
cancel the secret key import in this case. */
release_kbnode (pub_keyblock);
/* Read the keyblock again to get the effects of a merge. */
/* Fixme: we should do this based on the fingerprint or
even better let import_one return the merged
@ -1493,7 +1617,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
if (!opt.quiet)
log_info (_("key %s: secret key imported\n"),
keystr_from_pk (pk));
if (is_status_enabled ())
if (is_status_enabled ())
print_import_ok (pk, 1|16);
check_prefs (ctrl, node);
}
@ -1502,11 +1626,11 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
}
}
else
{
{
/* We don't want to merge the secret keys. */
log_error (_("key %s: secret key part already available\n"),
keystr_from_pk (pk));
if (is_status_enabled ())
if (is_status_enabled ())
print_import_ok (pk, 16);
}
@ -1556,9 +1680,9 @@ import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats )
{
byte afp[MAX_FINGERPRINT_LEN];
size_t an;
fingerprint_from_pk (pk, afp, &an);
while (an < MAX_FINGERPRINT_LEN)
while (an < MAX_FINGERPRINT_LEN)
afp[an++] = 0;
rc = keydb_search_fpr (hd, afp);
}
@ -1654,11 +1778,11 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
int rc;
u32 bsdate=0, rsdate=0;
kbnode_t bsnode = NULL, rsnode = NULL;
(void)fname;
(void)pk;
for (n=keyblock; (n = find_next_kbnode (n, 0)); )
for (n=keyblock; (n = find_next_kbnode (n, 0)); )
{
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
@ -1672,7 +1796,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
if ( n->pkt->pkttype != PKT_SIGNATURE )
continue;
sig = n->pkt->pkt.signature;
if ( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
{
@ -1684,7 +1808,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
import a fully-cached key which speeds things up. */
if (!opt.no_sig_cache)
check_key_signature (keyblock, n, NULL);
if ( IS_UID_SIG(sig) || IS_UID_REV(sig) )
{
KBNODE unode = find_prev_kbnode( keyblock, n, PKT_USER_ID );
@ -1694,16 +1818,16 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
keystr(keyid));
return -1; /* The complete keyblock is invalid. */
}
/* If it hasn't been marked valid yet, keep trying. */
if (!(unode->flag&1))
if (!(unode->flag&1))
{
rc = check_key_signature (keyblock, n, NULL);
if ( rc )
{
if ( opt.verbose )
{
char *p = utf8_to_native
char *p = utf8_to_native
(unode->pkt->pkt.user_id->name,
strlen (unode->pkt->pkt.user_id->name),0);
log_info (gpg_err_code(rc) == G10ERR_PUBKEY_ALGO ?
@ -1732,7 +1856,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
n->flag |= 4;
}
}
else if ( IS_SUBKEY_SIG (sig) )
else if ( IS_SUBKEY_SIG (sig) )
{
/* Note that this works based solely on the timestamps like
the rest of gpg. If the standard gets revocation
@ -1761,19 +1885,19 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
else
{
/* It's valid, so is it newer? */
if (sig->timestamp >= bsdate)
if (sig->timestamp >= bsdate)
{
knode->flag |= 1; /* The subkey is valid. */
if (bsnode)
{
/* Delete the last binding sig since this
one is newer */
bsnode->flag |= 4;
bsnode->flag |= 4;
if (opt.verbose)
log_info (_("key %s: removed multiple subkey"
" binding\n"),keystr(keyid));
}
bsnode = n;
bsdate = sig->timestamp;
}
@ -1818,12 +1942,12 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
{
/* Delete the last revocation sig since
this one is newer. */
rsnode->flag |= 4;
rsnode->flag |= 4;
if (opt.verbose)
log_info (_("key %s: removed multiple subkey"
" revocation\n"),keystr(keyid));
}
rsnode = n;
rsdate = sig->timestamp;
}

File diff suppressed because it is too large Load Diff

View File

@ -39,7 +39,7 @@
#ifdef HAVE_UNSIGNED_TIME_T
# define IS_INVALID_TIME_T(a) ((a) == (time_t)(-1))
#else
#else
/* Error or 32 bit time_t and value after 2038-01-19. */
# define IS_INVALID_TIME_T(a) ((a) < 0)
#endif
@ -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];
}
}
}
@ -117,7 +139,7 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
u16 days=0;
if(pk->expiredate)
days=(u16)((pk->expiredate - pk->timestamp) / 86400L);
gcry_md_putc ( md, days >> 8 );
gcry_md_putc ( md, days );
}
@ -168,7 +190,7 @@ v3_keyid (gcry_mpi_t a, u32 *ki)
BUG ();
if (nbytes < 8) /* oops */
ki[0] = ki[1] = 0;
else
else
{
p = buffer + nbytes - 8;
ki[0] = (p[0] << 24) | (p[1] <<16) | (p[2] << 8) | p[3];
@ -205,7 +227,7 @@ keystrlen(void)
const char *
keystr (u32 *keyid)
{
{
static char keyid_str[KEYID_STR_SIZE];
switch (opt.keyid_format)
@ -216,7 +238,7 @@ keystr (u32 *keyid)
case KF_LONG:
if (keyid[0])
snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX",
snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX",
(ulong)keyid[0], (ulong)keyid[1]);
else
snprintf (keyid_str, sizeof keyid_str, "%08lX", (ulong)keyid[1]);
@ -228,12 +250,12 @@ keystr (u32 *keyid)
case KF_0xLONG:
if(keyid[0])
snprintf (keyid_str, sizeof keyid_str, "0x%08lX%08lX",
snprintf (keyid_str, sizeof keyid_str, "0x%08lX%08lX",
(ulong)keyid[0],(ulong)keyid[1]);
else
snprintf (keyid_str, sizeof keyid_str, "0x%08lX", (ulong)keyid[1]);
break;
default:
BUG();
}
@ -244,7 +266,7 @@ keystr (u32 *keyid)
const char *
keystr_with_sub (u32 *main_kid, u32 *sub_kid)
{
{
static char buffer[KEYID_STR_SIZE+1+KEYID_STR_SIZE];
char *p;
@ -398,7 +420,7 @@ keyid_from_fingerprint( const byte *fprint, size_t fprint_len, u32 *keyid )
else
keyid_from_pk (&pk, keyid);
}
else
else
{
const byte *dp = fprint;
keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
@ -412,7 +434,7 @@ keyid_from_fingerprint( const byte *fprint, size_t fprint_len, u32 *keyid )
u32
keyid_from_sig (PKT_signature *sig, u32 *keyid)
{
if( keyid )
if( keyid )
{
keyid[0] = sig->keyid[0];
keyid[1] = sig->keyid[1];
@ -427,13 +449,13 @@ namehash_from_uid (PKT_user_id *uid)
if (!uid->namehash)
{
uid->namehash = xmalloc (20);
if (uid->attrib_data)
rmd160_hash_buffer (uid->namehash, uid->attrib_data, uid->attrib_len);
else
rmd160_hash_buffer (uid->namehash, uid->name, uid->len);
}
return uid->namehash;
}
@ -455,7 +477,7 @@ mk_datestr (char *buffer, time_t atime)
if (IS_INVALID_TIME_T (atime))
strcpy (buffer, "????" "-??" "-??"); /* Mark this as invalid. */
else
else
{
tp = gmtime (&atime);
sprintf (buffer,"%04d-%02d-%02d",
@ -475,7 +497,7 @@ datestr_from_pk (PKT_public_key *pk)
{
static char buffer[11+5];
time_t atime = pk->timestamp;
return mk_datestr (buffer, atime);
}
@ -508,7 +530,7 @@ expirestr_from_sig (PKT_signature *sig)
{
static char buffer[11+5];
time_t atime;
if (!sig->expiredate)
return _("never ");
atime=sig->expiredate;
@ -581,7 +603,7 @@ const char *
colon_datestr_from_sig (PKT_signature *sig)
{
static char buf[20];
snprintf (buf, sizeof buf, "%lu", (ulong)sig->timestamp);
return buf;
}
@ -611,21 +633,21 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
const byte *dp;
size_t len, nbytes;
int i;
if ( pk->version < 4 )
{
if ( is_RSA(pk->pubkey_algo) )
{
/* RSA in version 3 packets is special. */
gcry_md_hd_t md;
if (gcry_md_open (&md, DIGEST_ALGO_MD5, 0))
BUG ();
if ( pubkey_get_npkey (pk->pubkey_algo) > 1 )
if ( pubkey_get_npkey (pk->pubkey_algo) > 1 )
{
for (i=0; i < 2; i++)
{
if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0,
if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0,
&nbytes, pk->pkey[i]))
BUG ();
/* fixme: Better allocate BUF on the stack */
@ -652,10 +674,10 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
memset (array,0,16);
}
}
else
else
{
gcry_md_hd_t md;
md = do_fingerprint_md(pk);
dp = gcry_md_read( md, 0 );
len = gcry_md_get_algo_dlen (gcry_md_get_algo (md));
@ -667,7 +689,7 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
pk->keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
gcry_md_close( md);
}
*ret_len = len;
return array;
}
@ -684,7 +706,7 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
{
gpg_error_t err;
gcry_sexp_t s_pkey;
if (DBG_PACKET)
log_debug ("get_keygrip for public key\n");
@ -712,11 +734,27 @@ 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;
}
if (err)
return err;
@ -732,7 +770,7 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
/* FIXME: Save the keygrip in PK. */
}
gcry_sexp_release (s_pkey);
return 0;
}
@ -760,4 +798,3 @@ hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip)
}
return err;
}

View File

@ -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 );

View File

@ -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));

View File

@ -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;
}

View File

@ -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 );

View File

@ -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);

View File

@ -74,7 +74,7 @@ encode_s2k_iterations (int iterations)
if (err && gpg_err_code (err) != GPG_ERR_ASS_PARAMETER)
log_error (_("problem with the agent: %s\n"), gpg_strerror (err));
/* Default to 65536 which we used up to 2.0.13. */
return 96;
return 96;
}
else if (mycnt >= 65011712)
return 255; /* Largest possible value. */
@ -87,7 +87,7 @@ encode_s2k_iterations (int iterations)
if (iterations >= 65011712)
return 255;
/* Need count to be in the range 16-31 */
for (count=iterations>>6; count>=32; count>>=1)
c++;
@ -96,13 +96,13 @@ encode_s2k_iterations (int iterations)
if (S2K_DECODE_COUNT(result) < iterations)
result++;
return result;
}
/* Hash a passphrase using the supplied s2k.
/* Hash a passphrase using the supplied s2k.
Always needs: dek->algo, s2k->mode, s2k->hash_algo. */
static void
hash_passphrase ( DEK *dek, char *pw, STRING2KEY *s2k)
@ -119,20 +119,20 @@ hash_passphrase ( DEK *dek, char *pw, STRING2KEY *s2k)
if (gcry_md_open (&md, s2k->hash_algo, 1))
BUG ();
for (pass=0; used < dek->keylen ; pass++ )
for (pass=0; used < dek->keylen ; pass++ )
{
if ( pass )
if ( pass )
{
gcry_md_reset (md);
for (i=0; i < pass; i++ ) /* Preset the hash context. */
gcry_md_putc (md, 0 );
}
if ( s2k->mode == 1 || s2k->mode == 3 )
if ( s2k->mode == 1 || s2k->mode == 3 )
{
int len2 = pwlen + 8;
ulong count = len2;
if ( s2k->mode == 3 )
{
count = S2K_DECODE_COUNT(s2k->count);
@ -146,7 +146,7 @@ hash_passphrase ( DEK *dek, char *pw, STRING2KEY *s2k)
/* A little bit complicated because we need a ulong for count. */
while ( count > len2 ) /* maybe iterated+salted */
{
{
gcry_md_write ( md, s2k->salt, 8 );
gcry_md_write ( md, pw, pwlen );
count -= len2;
@ -231,7 +231,7 @@ read_passphrase_from_fd( int fd )
int i, len;
char *pw;
if ( !opt.batch )
if ( !opt.batch )
{ /* Not used but we have to do a dummy read, so that it won't end
up at the begin of the message if the quite usual trick to
prepend the passphtrase to the message is used. */
@ -240,12 +240,12 @@ read_passphrase_from_fd( int fd )
while (!(read (fd, buf, 1) != 1 || *buf == '\n' ))
;
*buf = 0;
return;
return;
}
for (pw = NULL, i = len = 100; ; i++ )
for (pw = NULL, i = len = 100; ; i++ )
{
if (i >= len-1 )
if (i >= len-1 )
{
char *pw2 = pw;
len += 100;
@ -311,35 +311,35 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat,
if( keyid && get_pubkey( pk, keyid ) )
{
if (pk)
free_public_key( pk );
free_public_key( pk );
pk = NULL; /* oops: no key for some reason */
}
orig_codeset = i18n_switchto_utf8 ();
if (custom_description)
atext = native_to_utf8 (custom_description);
else if ( !mode && pk && keyid )
{
{
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;
if ( !algo_name )
algo_name = "?";
#define KEYIDSTRING _(" (main key ID %s)")
maink = xmalloc ( strlen (KEYIDSTRING) + keystrlen() + 20 );
if( keyid[2] && keyid[3] && keyid[0] != keyid[2]
if( keyid[2] && keyid[3] && keyid[0] != keyid[2]
&& keyid[1] != keyid[3] )
sprintf( maink, KEYIDSTRING, keystr(&keyid[2]) );
else
*maink = 0;
uid = get_user_id ( keyid, &uidlen );
uid = get_user_id ( keyid, &uidlen );
timestr = strtimestamp (pk->timestamp);
#undef KEYIDSTRING
@ -350,7 +350,7 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat,
"%u-bit %s key, ID %s,\n" \
"created %s%s.\n" )
atext = xmalloc ( 100 + strlen (PROMPTSTRING)
atext = xmalloc ( 100 + strlen (PROMPTSTRING)
+ uidlen + 15 + strlen(algo_name) + keystrlen()
+ strlen (timestr) + strlen (maink) );
sprintf (atext, PROMPTSTRING,
@ -362,16 +362,16 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat,
#undef PROMPTSTRING
{
{
size_t dummy;
fingerprint_from_pk( pk, fpr, &dummy );
have_fpr = 1;
}
}
else
atext = xstrdup ( _("Enter passphrase\n") );
if (!mode && cacheid)
my_cacheid = cacheid;
@ -387,7 +387,7 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat,
rc = agent_get_passphrase (my_cacheid, tryagain_text, my_prompt, atext,
repeat, check, &pw);
xfree (my_prompt);
xfree (atext); atext = NULL;
@ -396,14 +396,14 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat,
if (!rc)
;
else if (gpg_err_code (rc) == GPG_ERR_CANCELED
else if (gpg_err_code (rc) == GPG_ERR_CANCELED
|| gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
{
log_info (_("cancelled by user\n") );
if (canceled)
*canceled = 1;
}
else
else
{
log_error (_("problem with the agent: %s\n"), gpg_strerror (rc));
/* Due to limitations in the API of the upper layers they
@ -412,7 +412,7 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat,
definitely not happen and let it continue without requiring a
passphrase. Given that now all the upper layers handle a
cancel correctly, we simply set the cancel flag now for all
errors from the agent. */
errors from the agent. */
if (canceled)
*canceled = 1;
@ -440,7 +440,7 @@ passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo )
int rc;
(void)algo;
if (!cacheid)
{
PKT_public_key *pk;
@ -450,7 +450,7 @@ passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo )
byte fpr[MAX_FINGERPRINT_LEN];
char hexfprbuf[2*20+1];
size_t dummy;
pk = xcalloc (1, sizeof *pk);
if ( !keyid || get_pubkey( pk, keyid ) )
{
@ -478,7 +478,7 @@ passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo )
NULL, sets it to true.
MODE 0: Allow cached passphrase
1: Ignore cached passphrase
1: Ignore cached passphrase
2: Ditto, but create a new key
3: Allow cached passphrase; use the S2K salt as the cache ID
4: Ditto, but create a new key
@ -486,7 +486,7 @@ passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo )
DEK *
passphrase_to_dek_ext (u32 *keyid, int pubkey_algo,
int cipher_algo, STRING2KEY *s2k, int mode,
const char *tryagain_text,
const char *tryagain_text,
const char *custdesc, const char *custprompt,
int *canceled)
{
@ -499,11 +499,11 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo,
if (!canceled)
canceled = &dummy_canceled;
*canceled = 0;
if ( !s2k )
{
assert (mode != 3 && mode != 4);
/* This is used for the old rfc1991 mode
/* This is used for the old rfc1991 mode
* Note: This must match the code in encode.c with opt.rfc1991 set */
s2k = &help_s2k;
s2k->mode = 0;
@ -529,16 +529,16 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo,
/* If we do not have a passphrase available in NEXT_PW and status
information are request, we print them now. */
if ( !next_pw && is_status_enabled() )
if ( !next_pw && is_status_enabled() )
{
char buf[50];
if ( keyid )
{
u32 used_kid[2];
char *us;
if ( keyid[2] && keyid[3] )
if ( keyid[2] && keyid[3] )
{
used_kid[0] = keyid[2];
used_kid[1] = keyid[3];
@ -548,16 +548,16 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo,
used_kid[0] = keyid[0];
used_kid[1] = keyid[1];
}
us = get_long_user_id_string ( keyid );
write_status_text ( STATUS_USERID_HINT, us );
xfree(us);
snprintf (buf, sizeof buf -1, "%08lX%08lX %08lX%08lX %d 0",
(ulong)keyid[0], (ulong)keyid[1],
(ulong)used_kid[0], (ulong)used_kid[1],
pubkey_algo );
write_status_text ( STATUS_NEED_PASSPHRASE, buf );
}
else
@ -576,7 +576,7 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo,
{
PKT_public_key *pk = xmalloc_clear( sizeof *pk );
char *p;
p = get_user_id_native(keyid);
tty_printf ("\n");
tty_printf (_("You need a passphrase to unlock the secret key for\n"
@ -585,8 +585,8 @@ 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),
strtimestamp(pk->timestamp) );
@ -610,19 +610,19 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo,
free_public_key( pk );
}
if ( next_pw )
if ( next_pw )
{
/* Simply return the passphrase we already have in NEXT_PW. */
pw = next_pw;
next_pw = NULL;
}
else if ( have_static_passphrase () )
else if ( have_static_passphrase () )
{
/* Return the passphrase we have stored in FD_PASSWD. */
pw = xmalloc_secure ( strlen(fd_passwd)+1 );
strcpy ( pw, fd_passwd );
}
else
else
{
if ((mode == 3 || mode == 4) && (s2k->mode == 1 || s2k->mode == 3))
{
@ -643,7 +643,7 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo,
return NULL;
}
}
if ( !pw || !*pw )
write_status( STATUS_MISSING_PASSPHRASE );
@ -689,15 +689,15 @@ gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped)
char *maink;
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);
uid = get_user_id (pk->keyid, &uidlen);
orig_codeset = i18n_switchto_utf8 ();
if (pk->main_keyid[0] && pk->main_keyid[1]
&& pk->keyid[0] != pk->main_keyid[0]
&& pk->keyid[0] != pk->main_keyid[0]
&& pk->keyid[1] != pk->main_keyid[1])
maink = xtryasprintf (_(" (main key ID %s)"), keystr (pk->main_keyid));
else
@ -724,7 +724,7 @@ gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped)
"created %s%s.\n"),
prompt,
(int)uidlen, uid,
nbits_from_pk (pk), algo_name,
nbits_from_pk (pk), algo_name,
keystr (pk->keyid), timestr,
maink?maink:"" );
xfree (maink);
@ -735,7 +735,7 @@ gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped)
if (escaped)
{
char *tmp = percent_plus_escape (desc);
xfree (desc);
xfree (desc);
desc = tmp;
}

View File

@ -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,14 +27,17 @@
#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;
gcry_mpi_t data;
list = gcry_sexp_find_token (sexp, item, 0);
assert (list);
data = gcry_sexp_nth_mpi (list, 1, 0);
@ -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;
}

View File

@ -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*/

View File

@ -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,15 +155,15 @@ 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);
else
err = gcry_sexp_build (&s_data, NULL, "(enc-val(elg(a%m)(b%m)))",
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;
}

View File

@ -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"
@ -48,10 +49,10 @@ make_session_key( DEK *dek )
0 : GCRY_CIPHER_ENABLE_SYNC))) )
BUG();
gcry_randomize (dek->key, dek->keylen, GCRY_STRONG_RANDOM );
for (i=0; i < 16; i++ )
for (i=0; i < 16; i++ )
{
rc = gcry_cipher_setkey (chd, dek->key, dek->keylen);
if (!rc)
if (!rc)
{
gcry_cipher_close (chd);
return;
@ -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();

View File

@ -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,10 +436,15 @@ 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
160-bit hash unless --enable-dsa2 is set, in which case act
@ -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;
}

View File

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

View File

@ -40,6 +40,5 @@ const void *next_tuple (tupledesc_t tupledesc,
unsigned int *r_tag, size_t *r_length);
#endif /*G13_UTILS_H*/

View File

@ -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.

View File

@ -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

View File

@ -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);
}

2088
po/de.po

File diff suppressed because it is too large Load Diff

View File

@ -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).

View 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-----

View 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-----