mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Merge branch 'ECC-INTEGRATION-2-1'
This commit is contained in:
commit
38904b697c
132
.gitignore
vendored
132
.gitignore
vendored
@ -4,9 +4,141 @@ autom4te.cache/
|
||||
configure
|
||||
config.h.in
|
||||
config.h
|
||||
config.log
|
||||
config.status
|
||||
common/audit-events.h
|
||||
common/status-codes.h
|
||||
doc/gnupg.info*
|
||||
doc/stamp-vti
|
||||
doc/version.texi
|
||||
po/gnupg2.pot
|
||||
po/POTFILES
|
||||
stamp-h1
|
||||
Makefile
|
||||
.deps/
|
||||
keyserver/gpg2keys_mailto
|
||||
keyserver/gpg2keys_test
|
||||
tools/gpg-zip
|
||||
|
||||
# Files created by make when not using a VPATH build
|
||||
*.o
|
||||
po/en@boldquot.insert-header
|
||||
po/en@boldquot.po
|
||||
po/en@quot.insert-header
|
||||
po/en@quot.po
|
||||
po/stamp-po
|
||||
agent/gpg-agent
|
||||
agent/gpg-preset-passphrase
|
||||
agent/gpg-protect-tool
|
||||
agent/t-protect
|
||||
common/libcommon.a
|
||||
common/libcommonpth.a
|
||||
common/libgpgrl.a
|
||||
common/libsimple-pwquery.a
|
||||
common/t-b64
|
||||
common/t-convert
|
||||
common/t-exechelp
|
||||
common/t-gettime
|
||||
common/t-helpfile
|
||||
common/t-percent
|
||||
common/t-session-env
|
||||
common/t-sexputil
|
||||
common/t-sysutils
|
||||
common/t-stringhelp
|
||||
common/t-timestuff
|
||||
doc/addgnupghome.8
|
||||
doc/applygnupgdefaults.8
|
||||
doc/faq.html
|
||||
doc/faq.raw.xref
|
||||
doc/gnupg-card-architecture.eps
|
||||
doc/gnupg-card-architecture.pdf
|
||||
doc/gnupg-card-architecture.png
|
||||
doc/gnupg.7
|
||||
doc/gpg-agent.1
|
||||
doc/gpg-connect-agent.1
|
||||
doc/gpg-preset-passphrase.1
|
||||
doc/gpg-zip.1
|
||||
doc/gpg2.1
|
||||
doc/gpgconf.1
|
||||
doc/gpgparsemail.1
|
||||
doc/gpgsm-gencert.sh.1
|
||||
doc/gpgsm.1
|
||||
doc/gpgv2.1
|
||||
doc/scdaemon.1
|
||||
doc/dirmngr-client.1
|
||||
doc/dirmngr.8
|
||||
doc/symcryptrun.1
|
||||
doc/watchgnupg.1
|
||||
doc/yat2m
|
||||
doc/yat2m-stamp
|
||||
g10/gpg2
|
||||
g10/gpgv2
|
||||
g10/t-rmd160
|
||||
gl/alloca.h
|
||||
gl/libgnu.a
|
||||
jnlib/libjnlib.a
|
||||
jnlib/t-stringhelp
|
||||
kbx/kbxutil
|
||||
kbx/libkeybox.a
|
||||
keyserver/gpg2keys_curl
|
||||
keyserver/gpg2keys_finger
|
||||
keyserver/gpg2keys_hkp
|
||||
keyserver/gpg2keys_kdns
|
||||
keyserver/gpg2keys_ldap
|
||||
scd/gnupg-pcsc-wrapper
|
||||
scd/scdaemon
|
||||
sm/gpgsm
|
||||
dirmngr/dirmngr
|
||||
dirmngr/dirmngr-client
|
||||
dirmngr/dirmngr_ldap
|
||||
dirmngr/no-libgcrypt.c
|
||||
tests/asschk
|
||||
tests/gpg-agent.conf
|
||||
tests/gpgsm.conf
|
||||
tests/inittests.stamp
|
||||
tests/openpgp/data-32000
|
||||
tests/openpgp/data-500
|
||||
tests/openpgp/data-80000
|
||||
tests/openpgp/data-9000
|
||||
tests/openpgp/gpg-agent.conf
|
||||
tests/openpgp/gpg_dearmor
|
||||
tests/openpgp/plain-1
|
||||
tests/openpgp/plain-2
|
||||
tests/openpgp/plain-3
|
||||
tests/openpgp/plain-large
|
||||
tests/openpgp/prepared.stamp
|
||||
tests/openpgp/pubring.gpg
|
||||
tests/openpgp/pubring.pkr
|
||||
tests/openpgp/secring.gpg
|
||||
tests/openpgp/secring.skr
|
||||
tests/pkits/ReadMe.txt
|
||||
tests/pkits/certpairs/
|
||||
tests/pkits/certs/
|
||||
tests/pkits/crls/
|
||||
tests/pkits/gpg-agent.conf
|
||||
tests/pkits/gpgsm.conf
|
||||
tests/pkits/inittests.stamp
|
||||
tests/pkits/pkcs12/
|
||||
tests/pkits/pkits.ldif
|
||||
tests/pkits/pkits.schema
|
||||
tests/pkits/policies.txt
|
||||
tests/pkits/smime/
|
||||
tests/pkits/testdir.stamp
|
||||
tests/pkits/trustlist.txt
|
||||
tests/private-keys-v1.d/
|
||||
tests/pubring.kbx
|
||||
tests/testdir.stamp
|
||||
tests/trustlist.txt
|
||||
tools/clean-sat
|
||||
tools/gpg-check-pattern
|
||||
tools/gpg-connect-agent
|
||||
tools/gpgconf
|
||||
tools/gpgkey2ssh
|
||||
tools/gpgparsemail
|
||||
tools/gpgsplit
|
||||
tools/make-dns-cert
|
||||
tools/mk-tdata
|
||||
tools/symcryptrun
|
||||
tools/watchgnupg
|
||||
tools/gpgtar
|
||||
g13/g13
|
||||
|
4
AUTHORS
4
AUTHORS
@ -11,6 +11,9 @@ Authors
|
||||
|
||||
Ales Nyakhaychyk <nyakhaychyk@i1fn.linux.by> Translations [be]
|
||||
|
||||
Andrey Jivsov <openpgp@brainhub.org> Assigns past and future changes for ECC.
|
||||
(g10/ecdh.c. other changes to support ECC)
|
||||
|
||||
Birger Langkjer <birger.langkjer@image.dk> Translations [da]
|
||||
|
||||
Maxim Britov <maxim.britov@gmail.com> Translations [ru]
|
||||
@ -174,4 +177,3 @@ name gpg2keys_*.
|
||||
This file is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
2011-02-01 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac (HAVE_GCRY_PK_GET_CURVE): Define if availabale.
|
||||
|
||||
2011-01-20 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac (AC_CONFIG_FILES): Remove keyserver/.
|
||||
@ -8,6 +12,11 @@
|
||||
(NAME_OF_INSTALLED_GPG): New ac_define.
|
||||
* autogen.sh [--build-w32ce]: Use --enable-gpg2-is-gpg.
|
||||
|
||||
2011-01-21 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac: Need Libgcrypt 1.4.6 due to AESWRAP.
|
||||
(HAVE_GCRY_PK_ECDH): Add new test.
|
||||
|
||||
2011-01-03 Werner Koch <wk@g10code.com>
|
||||
|
||||
* README.SVN: Rename to README.GIT.
|
||||
|
18
NEWS
18
NEWS
@ -20,6 +20,8 @@ Noteworthy changes in version 2.1.0beta2 (unreleased)
|
||||
* Dirmngr has taken over the function of the keyserver helpers. Thus
|
||||
we now have a specified direct interface to keyservers via Dirmngr.
|
||||
|
||||
* ECC support for GPG as described by draft-jivsov-openpgp-ecc-06.txt.
|
||||
|
||||
|
||||
Noteworthy changes in version 2.1.0beta1 (2010-10-26)
|
||||
-----------------------------------------------------
|
||||
@ -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
|
||||
|
129
agent/ChangeLog
129
agent/ChangeLog
@ -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>
|
||||
|
||||
|
@ -215,6 +215,7 @@ const char *get_agent_ssh_socket_name (void);
|
||||
void *get_agent_scd_notify_event (void);
|
||||
#endif
|
||||
void agent_sighup_action (void);
|
||||
int map_pk_openpgp_to_gcry (int openpgp_algo);
|
||||
|
||||
/*-- command.c --*/
|
||||
gpg_error_t agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid);
|
||||
|
@ -28,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;
|
||||
}
|
||||
|
||||
|
@ -726,6 +726,16 @@ key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list,
|
||||
algoname = "dsa";
|
||||
elems = "pqgy";
|
||||
}
|
||||
else if (n==5 && !memcmp (name, "ecdsa", 5))
|
||||
{
|
||||
algoname = "ecdsa";
|
||||
elems = "pabgnq";
|
||||
}
|
||||
else if (n==4 && !memcmp (name, "ecdh", 4))
|
||||
{
|
||||
algoname = "ecdh";
|
||||
elems = "pabgnq";
|
||||
}
|
||||
else if (n==3 && !memcmp (name, "elg", 3))
|
||||
{
|
||||
algoname = "elg";
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "gc-opt-flags.h"
|
||||
#include "exechelp.h"
|
||||
#include "asshelp.h"
|
||||
#include "../include/cipher.h" /* for PUBKEY_ALGO_ECDSA, PUBKEY_ALGO_ECDH */
|
||||
|
||||
enum cmd_and_opt_values
|
||||
{ aNull = 0,
|
||||
@ -2301,3 +2302,12 @@ check_for_running_agent (int silent, int mode)
|
||||
assuan_release (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: it is also in misc, which is not linked with the agent */
|
||||
/* FIXME: The agent should not know about openpgp internals - weel
|
||||
except for some stuff in cvt-openpgp. */
|
||||
int
|
||||
map_pk_openpgp_to_gcry (int algo)
|
||||
{
|
||||
return (algo==PUBKEY_ALGO_ECDSA ? GCRY_PK_ECDSA : (algo==PUBKEY_ALGO_ECDH ? GCRY_PK_ECDH : algo));
|
||||
}
|
||||
|
@ -113,18 +113,21 @@ get_dsa_qbits (gcry_sexp_t key)
|
||||
|
||||
/* Encode a message digest for use with an DSA algorithm. */
|
||||
static gpg_error_t
|
||||
do_encode_dsa (const byte * md, size_t mdlen, int dsaalgo, gcry_sexp_t pkey,
|
||||
do_encode_dsa (const byte *md, size_t mdlen, int dsaalgo, gcry_sexp_t pkey,
|
||||
gcry_sexp_t *r_hash)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gcry_sexp_t hash;
|
||||
unsigned int qbits;
|
||||
int pkalgo;
|
||||
|
||||
*r_hash = NULL;
|
||||
|
||||
if (dsaalgo == GCRY_PK_ECDSA)
|
||||
pkalgo = map_pk_openpgp_to_gcry (dsaalgo);
|
||||
|
||||
if (pkalgo == GCRY_PK_ECDSA)
|
||||
qbits = gcry_pk_get_nbits (pkey);
|
||||
else if (dsaalgo == GCRY_PK_DSA)
|
||||
else if (pkalgo == GCRY_PK_DSA)
|
||||
qbits = get_dsa_qbits (pkey);
|
||||
else
|
||||
return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
|
||||
@ -143,20 +146,28 @@ do_encode_dsa (const byte * md, size_t mdlen, int dsaalgo, gcry_sexp_t pkey,
|
||||
if (qbits < 160)
|
||||
{
|
||||
log_error (_("%s key uses an unsafe (%u bit) hash\n"),
|
||||
gcry_pk_algo_name (dsaalgo), qbits);
|
||||
gcry_pk_algo_name (pkalgo), qbits);
|
||||
return gpg_error (GPG_ERR_INV_LENGTH);
|
||||
}
|
||||
|
||||
/* Check if we're too short. Too long is safe as we'll
|
||||
automatically left-truncate. */
|
||||
if (mdlen < qbits/8)
|
||||
* automatically left-truncate.
|
||||
*
|
||||
* This check would require the use of SHA512 with ECDSA 512. I
|
||||
* think this is overkill to fail in this case. Therefore, relax
|
||||
* the check, but only for ECDSA keys. We may need to adjust it
|
||||
* later for general case. (Note that the check is really a bug for
|
||||
* ECDSA 521 as the only hash that matches it is SHA 512, but 512 <
|
||||
* 521 ).
|
||||
*/
|
||||
if (mdlen < ((pkalgo==GCRY_PK_ECDSA && qbits > 521) ? 512 : qbits)/8)
|
||||
{
|
||||
log_error (_("a %zu bit hash is not valid for a %u bit %s key\n"),
|
||||
mdlen*8,
|
||||
gcry_pk_get_nbits (pkey),
|
||||
gcry_pk_algo_name (dsaalgo));
|
||||
gcry_pk_algo_name (pkalgo));
|
||||
/* FIXME: we need to check the requirements for ECDSA. */
|
||||
if (mdlen < 20 || dsaalgo == GCRY_PK_DSA)
|
||||
if (mdlen < 20 || pkalgo == GCRY_PK_DSA)
|
||||
return gpg_error (GPG_ERR_INV_LENGTH);
|
||||
}
|
||||
|
||||
|
172
agent/protect.c
172
agent/protect.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
2011-01-31 Werner Koch <wk@g10code.com>
|
||||
|
||||
* openpgp-oid.c: New.
|
||||
* t-openpgp-oid.c: New.
|
||||
|
||||
2011-01-20 Werner Koch <wk@g10code.com>
|
||||
|
||||
Fix bug#1313.
|
||||
|
@ -90,6 +90,7 @@ common_sources = \
|
||||
localename.c \
|
||||
session-env.c session-env.h \
|
||||
userids.c userids.h \
|
||||
openpgp-oid.c \
|
||||
helpfile.c
|
||||
|
||||
# To make the code easier to read we have split home some code into
|
||||
@ -160,7 +161,7 @@ if HAVE_W32_SYSTEM
|
||||
jnlib_tests += t-w32-reg
|
||||
endif
|
||||
module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil \
|
||||
t-session-env
|
||||
t-session-env t-openpgp-oid
|
||||
if !HAVE_W32CE_SYSTEM
|
||||
module_tests += t-exechelp
|
||||
endif
|
||||
@ -192,6 +193,7 @@ t_sexputil_LDADD = $(t_common_ldadd)
|
||||
t_b64_LDADD = $(t_common_ldadd)
|
||||
t_exechelp_LDADD = $(t_common_ldadd)
|
||||
t_session_env_LDADD = $(t_common_ldadd)
|
||||
t_openpgp_oid_LDADD = $(t_common_ldadd)
|
||||
|
||||
|
||||
|
||||
|
@ -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
227
common/openpgp-oid.c
Normal file
@ -0,0 +1,227 @@
|
||||
/* openpgp-oids.c - OID helper for OpenPGP
|
||||
* Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
|
||||
/* Helper for openpgp_oid_from_str. */
|
||||
static size_t
|
||||
make_flagged_int (unsigned long value, char *buf, size_t buflen)
|
||||
{
|
||||
int more = 0;
|
||||
int shift;
|
||||
|
||||
/* fixme: figure out the number of bits in an ulong and start with
|
||||
that value as shift (after making it a multiple of 7) a more
|
||||
straigtforward implementation is to do it in reverse order using
|
||||
a temporary buffer - saves a lot of compares */
|
||||
for (more=0, shift=28; shift > 0; shift -= 7)
|
||||
{
|
||||
if (more || value >= (1<<shift))
|
||||
{
|
||||
buf[buflen++] = 0x80 | (value >> shift);
|
||||
value -= (value >> shift) << shift;
|
||||
more = 1;
|
||||
}
|
||||
}
|
||||
buf[buflen++] = value;
|
||||
return buflen;
|
||||
}
|
||||
|
||||
|
||||
/* Convert the OID given in dotted decimal form in STRING to an DER
|
||||
* encoding and store it as an opaque value at R_MPI. The format of
|
||||
* the DER encoded is not a regular ASN.1 object but the modified
|
||||
* format as used by OpenPGP for the ECC curve description. On error
|
||||
* the function returns and error code an NULL is stored at R_BUG.
|
||||
* Note that scanning STRING stops at the first white space
|
||||
* character. */
|
||||
gpg_error_t
|
||||
openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi)
|
||||
{
|
||||
unsigned char *buf;
|
||||
size_t buflen;
|
||||
unsigned long val1, val;
|
||||
const char *endp;
|
||||
int arcno;
|
||||
|
||||
*r_mpi = NULL;
|
||||
|
||||
if (!string || !*string)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
/* We can safely assume that the encoded OID is shorter than the string. */
|
||||
buf = xtrymalloc (1 + strlen (string) + 2);
|
||||
if (!buf)
|
||||
return gpg_error_from_syserror ();
|
||||
/* Save the first byte for the length. */
|
||||
buflen = 1;
|
||||
|
||||
val1 = 0; /* Avoid compiler warning. */
|
||||
arcno = 0;
|
||||
do {
|
||||
arcno++;
|
||||
val = strtoul (string, (char**)&endp, 10);
|
||||
if (!digitp (string) || !(*endp == '.' || !*endp))
|
||||
{
|
||||
xfree (buf);
|
||||
return gpg_error (GPG_ERR_INV_OID_STRING);
|
||||
}
|
||||
if (*endp == '.')
|
||||
string = endp+1;
|
||||
|
||||
if (arcno == 1)
|
||||
{
|
||||
if (val > 2)
|
||||
break; /* Not allowed, error catched below. */
|
||||
val1 = val;
|
||||
}
|
||||
else if (arcno == 2)
|
||||
{ /* Need to combine the first two arcs in one octet. */
|
||||
if (val1 < 2)
|
||||
{
|
||||
if (val > 39)
|
||||
{
|
||||
xfree (buf);
|
||||
return gpg_error (GPG_ERR_INV_OID_STRING);
|
||||
}
|
||||
buf[buflen++] = val1*40 + val;
|
||||
}
|
||||
else
|
||||
{
|
||||
val += 80;
|
||||
buflen = make_flagged_int (val, buf, buflen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buflen = make_flagged_int (val, buf, buflen);
|
||||
}
|
||||
} while (*endp == '.');
|
||||
|
||||
if (arcno == 1 || buflen < 2 || buflen > 254 )
|
||||
{ /* It is not possible to encode only the first arc. */
|
||||
xfree (buf);
|
||||
return gpg_error (GPG_ERR_INV_OID_STRING);
|
||||
}
|
||||
|
||||
*buf = buflen - 1;
|
||||
*r_mpi = gcry_mpi_set_opaque (NULL, buf, buflen * 8);
|
||||
if (!*r_mpi)
|
||||
{
|
||||
xfree (buf);
|
||||
return gpg_error_from_syserror ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return a malloced string represenation of the OID in the opaque MPI
|
||||
A. In case of an error NULL is returned and ERRNO is set. */
|
||||
char *
|
||||
openpgp_oid_to_str (gcry_mpi_t a)
|
||||
{
|
||||
const unsigned char *buf;
|
||||
size_t length;
|
||||
char *string, *p;
|
||||
int n = 0;
|
||||
unsigned long val, valmask;
|
||||
|
||||
valmask = (unsigned long)0xfe << (8 * (sizeof (valmask) - 1));
|
||||
|
||||
if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
gpg_err_set_errno (EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = gcry_mpi_get_opaque (a, &length);
|
||||
length = (length+7)/8;
|
||||
|
||||
/* The first bytes gives the length; check consistency. */
|
||||
if (!length || buf[0] != length -1)
|
||||
{
|
||||
gpg_err_set_errno (EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
/* Skip length byte. */
|
||||
length--;
|
||||
buf++;
|
||||
|
||||
/* To calculate the length of the string we can safely assume an
|
||||
upper limit of 3 decimal characters per byte. Two extra bytes
|
||||
account for the special first octect */
|
||||
string = p = xtrymalloc (length*(1+3)+2+1);
|
||||
if (!string)
|
||||
return NULL;
|
||||
if (!buf || !length)
|
||||
{
|
||||
*p = 0;
|
||||
return string;
|
||||
}
|
||||
|
||||
if (buf[0] < 40)
|
||||
p += sprintf (p, "0.%d", buf[n]);
|
||||
else if (buf[0] < 80)
|
||||
p += sprintf (p, "1.%d", buf[n]-40);
|
||||
else {
|
||||
val = buf[n] & 0x7f;
|
||||
while ( (buf[n]&0x80) && ++n < length )
|
||||
{
|
||||
if ( (val & valmask) )
|
||||
goto badoid; /* Overflow. */
|
||||
val <<= 7;
|
||||
val |= buf[n] & 0x7f;
|
||||
}
|
||||
val -= 80;
|
||||
sprintf (p, "2.%lu", val);
|
||||
p += strlen (p);
|
||||
}
|
||||
for (n++; n < length; n++)
|
||||
{
|
||||
val = buf[n] & 0x7f;
|
||||
while ( (buf[n]&0x80) && ++n < length )
|
||||
{
|
||||
if ( (val & valmask) )
|
||||
goto badoid; /* Overflow. */
|
||||
val <<= 7;
|
||||
val |= buf[n] & 0x7f;
|
||||
}
|
||||
sprintf (p, ".%lu", val);
|
||||
p += strlen (p);
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
return string;
|
||||
|
||||
badoid:
|
||||
/* Return a special OID (gnu.gnupg.badoid) to indicate the error
|
||||
case. The OID is broken and thus we return one which can't do
|
||||
any harm. Formally this does not need to be a bad OID but an OID
|
||||
with an arc that can't be represented in a 32 bit word is more
|
||||
than likely corrupt. */
|
||||
xfree (string);
|
||||
return xtrystrdup ("1.3.6.1.4.1.11591.2.12242973");
|
||||
}
|
148
common/t-openpgp-oid.c
Normal file
148
common/t-openpgp-oid.c
Normal file
@ -0,0 +1,148 @@
|
||||
/* t-openpgp-oid.c - Module test for openpgp-oid.c
|
||||
* Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#define pass() do { ; } while(0)
|
||||
#define fail(a,e) \
|
||||
do { fprintf (stderr, "%s:%d: test %d failed (%s)\n", \
|
||||
__FILE__,__LINE__, (a), gpg_strerror (e)); \
|
||||
exit (1); \
|
||||
} while(0)
|
||||
|
||||
|
||||
static void
|
||||
test_openpgp_oid_from_str (void)
|
||||
{
|
||||
static char *sample_oids[] =
|
||||
{
|
||||
"0.0",
|
||||
"1.0",
|
||||
"1.2.3",
|
||||
"1.2.840.10045.3.1.7",
|
||||
"1.3.132.0.34",
|
||||
"1.3.132.0.35",
|
||||
NULL
|
||||
};
|
||||
gpg_error_t err;
|
||||
gcry_mpi_t a;
|
||||
int idx;
|
||||
char *string;
|
||||
unsigned char *p;
|
||||
unsigned int nbits;
|
||||
size_t length;
|
||||
|
||||
err = openpgp_oid_from_str ("", &a);
|
||||
if (gpg_err_code (err) != GPG_ERR_INV_VALUE)
|
||||
fail (0, err);
|
||||
gcry_mpi_release (a);
|
||||
|
||||
err = openpgp_oid_from_str (".", &a);
|
||||
if (gpg_err_code (err) != GPG_ERR_INV_OID_STRING)
|
||||
fail (0, err);
|
||||
gcry_mpi_release (a);
|
||||
|
||||
err = openpgp_oid_from_str ("0", &a);
|
||||
if (gpg_err_code (err) != GPG_ERR_INV_OID_STRING)
|
||||
fail (0, err);
|
||||
gcry_mpi_release (a);
|
||||
|
||||
for (idx=0; sample_oids[idx]; idx++)
|
||||
{
|
||||
err = openpgp_oid_from_str (sample_oids[idx], &a);
|
||||
if (err)
|
||||
fail (idx, err);
|
||||
|
||||
string = openpgp_oid_to_str (a);
|
||||
if (!string)
|
||||
fail (idx, gpg_error_from_syserror ());
|
||||
if (strcmp (string, sample_oids[idx]))
|
||||
fail (idx, 0);
|
||||
xfree (string);
|
||||
|
||||
p = gcry_mpi_get_opaque (a, &nbits);
|
||||
length = (nbits+7)/8;
|
||||
if (!p || !length || p[0] != length - 1)
|
||||
fail (idx, 0);
|
||||
|
||||
gcry_mpi_release (a);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_openpgp_oid_to_str (void)
|
||||
{
|
||||
static struct {
|
||||
const char *string;
|
||||
unsigned char der[10];
|
||||
} samples[] = {
|
||||
{ "1.2.840.10045.3.1.7",
|
||||
{8, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 }},
|
||||
|
||||
{ "1.3.132.0.34",
|
||||
{5, 0x2B, 0x81, 0x04, 0x00, 0x22 }},
|
||||
|
||||
{ "1.3.132.0.35",
|
||||
{ 5, 0x2B, 0x81, 0x04, 0x00, 0x23 }},
|
||||
|
||||
{ NULL }};
|
||||
gcry_mpi_t a;
|
||||
int idx;
|
||||
char *string;
|
||||
unsigned char *p;
|
||||
|
||||
for (idx=0; samples[idx].string; idx++)
|
||||
{
|
||||
p = xmalloc (samples[idx].der[0]+1);
|
||||
memcpy (p, samples[idx].der, samples[idx].der[0]+1);
|
||||
a = gcry_mpi_set_opaque (NULL, p, (samples[idx].der[0]+1)*8);
|
||||
if (!a)
|
||||
fail (idx, gpg_error_from_syserror ());
|
||||
|
||||
string = openpgp_oid_to_str (a);
|
||||
if (!string)
|
||||
fail (idx, gpg_error_from_syserror ());
|
||||
if (strcmp (string, samples[idx].string))
|
||||
fail (idx, 0);
|
||||
xfree (string);
|
||||
gcry_mpi_release (a);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
test_openpgp_oid_from_str ();
|
||||
test_openpgp_oid_to_str ();
|
||||
|
||||
return 0;
|
||||
}
|
@ -42,6 +42,12 @@
|
||||
#ifndef GPG_ERR_FULLY_CANCELED
|
||||
#define GPG_ERR_FULLY_CANCELED 198
|
||||
#endif
|
||||
#ifndef GPG_ERR_INV_CURVE
|
||||
#define GPG_ERR_INV_CURVE 187
|
||||
#endif
|
||||
#ifndef GPG_ERR_UNKNOWN_CURVE
|
||||
#define GPG_ERR_UNKNOWN_CURVE 188
|
||||
#endif
|
||||
|
||||
|
||||
/* Hash function used with libksba. */
|
||||
@ -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;
|
||||
|
34
configure.ac
34
configure.ac
@ -43,7 +43,7 @@ development_version=no
|
||||
NEED_GPG_ERROR_VERSION=1.8
|
||||
|
||||
NEED_LIBGCRYPT_API=1
|
||||
NEED_LIBGCRYPT_VERSION=1.4.0
|
||||
NEED_LIBGCRYPT_VERSION=1.4.6
|
||||
|
||||
NEED_LIBASSUAN_API=2
|
||||
NEED_LIBASSUAN_VERSION=2.0.0
|
||||
@ -742,6 +742,36 @@ AM_PATH_GPG_ERROR("$NEED_GPG_ERROR_VERSION",
|
||||
AM_PATH_LIBGCRYPT("$NEED_LIBGCRYPT_API:$NEED_LIBGCRYPT_VERSION",
|
||||
have_libgcrypt=yes,have_libgcrypt=no)
|
||||
|
||||
# fixme: We can remove the next two checks if we require libgcrypt 1.5.
|
||||
AC_CACHE_CHECK([whether Libgcrypt support ECDH], gnupg_cv_gcry_pk_ecdh,
|
||||
[ _gnupg_gcry_save_cflags=$CFLAGS
|
||||
CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS"
|
||||
AC_TRY_COMPILE(
|
||||
[#include <gcrypt.h>],
|
||||
[ return GCRY_PK_ECDH; ],
|
||||
gnupg_cv_gcry_pk_ecdh=yes,
|
||||
gnupg_cv_gcry_pk_ecdh=no)
|
||||
CFLAGS=$_gnupg_gcry_save_cflags])
|
||||
if test "$gnupg_cv_gcry_pk_ecdh" = yes; then
|
||||
AC_DEFINE([HAVE_GCRY_PK_ECDH], 1,
|
||||
[Define if gcrypt.h has the enum value for ECDH.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether Libgcrypt has gcry_pk_get_curve],
|
||||
gnupg_cv_gcry_pk_get_curve,
|
||||
[ _gnupg_gcry_save_cflags=$CFLAGS
|
||||
CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS"
|
||||
AC_TRY_COMPILE(
|
||||
[#include <gcrypt.h>],
|
||||
[ return gcry_pk_get_curve (NULL, 0, NULL); ],
|
||||
gnupg_cv_gcry_pk_get_curve=yes,
|
||||
gnupg_cv_gcry_pk_get_curve=no)
|
||||
CFLAGS=$_gnupg_gcry_save_cflags])
|
||||
if test "$gnupg_cv_gcry_pk_get_curve" = yes; then
|
||||
AC_DEFINE([HAVE_GCRY_PK_GET_CURVE], 1,
|
||||
[Define if gcrypt.h has gcry_pk_get_curve.])
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# libassuan is used for IPC
|
||||
@ -1484,7 +1514,7 @@ AC_ARG_ENABLE(optimization,
|
||||
AC_HELP_STRING([--disable-optimization],
|
||||
[disable compiler optimization]),
|
||||
[if test $enableval = no ; then
|
||||
CFLAGS=`echo $CFLAGS | sed 's/-O[[0-9]]//'`
|
||||
CFLAGS=`echo $CFLAGS | sed s/-O[[1-9]]\ /-O0\ /g`
|
||||
fi])
|
||||
|
||||
#
|
||||
|
@ -62,7 +62,7 @@ endif
|
||||
dirmngr_LDADD = $(libcommonpth) ../gl/libgnu.a $(DNSLIBS) $(LIBASSUAN_LIBS) \
|
||||
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(PTH_LIBS) $(LIBINTL) $(LIBICONV)
|
||||
if !USE_LDAPWRAPPER
|
||||
dirmngr_LDADD += $(LDAPLIBS)
|
||||
dirmngr_LDADD += $(LDAPLIBS) -llber #FIXME: Test for liblber first.
|
||||
endif
|
||||
dirmngr_LDFLAGS = $(extra_bin_ldflags)
|
||||
|
||||
|
139
g10/ChangeLog
139
g10/ChangeLog
@ -1,7 +1,87 @@
|
||||
2011-02-03 Werner Koch <wk@g10code.com>
|
||||
|
||||
Finished ECC integration.
|
||||
Wrote change description for 2011-01-13.
|
||||
|
||||
2011-02-02 Werner Koch <wk@g10code.com>
|
||||
|
||||
* encrypt.c (write_pubkey_enc_from_list): Don't compute the
|
||||
fingerprint.
|
||||
* pkglue.c (pk_encrypt): Replace PK_FP by PK and compute the
|
||||
fingerprint only when needed.
|
||||
* pkglue.h: Include packet.h.
|
||||
|
||||
* import.c (transfer_secret_keys): Make sure keyids are available.
|
||||
|
||||
* keyid.c (hash_public_key): Adjust for the ECC case.
|
||||
|
||||
2011-02-01 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpg.c (main): Call setup_libgcrypt_logging.
|
||||
|
||||
* import.c (transfer_secret_keys): Implement ECC case.
|
||||
(one_mpi_from_pkey): New.
|
||||
* export.c (transfer_format_to_openpgp): Ditto.
|
||||
* keygen.c (gpg_curve_to_oid): New.
|
||||
(ecckey_from_sexp): Factor curve name mapping out to new function.
|
||||
|
||||
2011-01-31 Werner Koch <wk@g10code.com>
|
||||
|
||||
* ecdh.c (pk_ecdh_encrypt_with_shared_point): Return an opaque MPI.
|
||||
|
||||
* build-packet.c (mpi_write): Rename to gpg_mpi_write and make global.
|
||||
|
||||
2011-01-30 Werner Koch <wk@g10code.com>
|
||||
|
||||
* keyid.c (keygrip_from_pk): Adjust ECC cases.
|
||||
* pkglue.c (pk_verify): Ditto.
|
||||
|
||||
* parse-packet.c (parse_key): Simply ECC case.
|
||||
(parse_pubkeyenc): Ditto.
|
||||
|
||||
* misc.c (pubkey_get_npkey): Special case ECC.
|
||||
(pubkey_get_nskey): Ditto.
|
||||
(mpi_print): Support printing of opaque values.
|
||||
(openpgp_oid_to_str): New.
|
||||
(pubkey_nbits): For ECC pass curve parameter.
|
||||
|
||||
* ecdh.c (pk_ecdh_default_params): Change to return an opaque MPI.
|
||||
|
||||
* build-packet.c (do_key): Automatically handle real and opaque
|
||||
key parameters.
|
||||
(write_fake_data): Return an error code.
|
||||
(mpi_write): Support writing opaque MPIs.
|
||||
(do_pubkey_enc): Simplify ECC handling.
|
||||
|
||||
2011-01-28 Werner Koch <wk@g10code.com>
|
||||
|
||||
* keygen.c (gen_ecc): Rewrite. Select a named curve and create a
|
||||
keyspec based on that.
|
||||
(pk_ecc_build_key_params): Remove.
|
||||
(get_parameter_algo): Map algo number.
|
||||
(ecckey_from_sexp): New.
|
||||
* misc.c (map_pk_gcry_to_openpgp): New.
|
||||
|
||||
2011-01-25 Werner Koch <wk@g10code.com>
|
||||
|
||||
* ecdh.c (pk_ecdh_default_params_to_mpi): Remove.
|
||||
(pk_ecdh_default_params): Rewrite. Factor KEK table out to ..
|
||||
(kek_params_table): .. here.
|
||||
(pk_ecdh_generate_ephemeral_key): New.
|
||||
(pk_ecdh_encrypt): Remove.
|
||||
(pk_ecdh_encrypt_with_shared_point): Make public.
|
||||
|
||||
* pubkey-enc.c (get_it): Fix assertion. Use GPG_ERR_WRONG_SECKEY
|
||||
instead of log_fatal. Add safety checks for NFRAME.
|
||||
|
||||
* keygen.c (pk_ecc_keypair_gen): Make static.
|
||||
(ask_keysize): Use proper rounding for ECC.
|
||||
(pk_ecc_build_key_params): Remove NBITSSTR.
|
||||
|
||||
2011-01-20 Werner Koch <wk@g10code.com>
|
||||
|
||||
* keyserver.c: Rewrite most stuff for use with dirmngr. Get rid
|
||||
of all spawn code. Work work pending.
|
||||
of all spawn code. More work pending.
|
||||
|
||||
* export.c (export_pubkeys_buffer): New.
|
||||
|
||||
@ -12,6 +92,57 @@
|
||||
* gpg.c: Include call-dirmngr.h.
|
||||
(gpg_deinit_default_ctrl): Call gpg_dirmngr_deinit_session_data.
|
||||
|
||||
2011-01-13 Andrey Jivsov <openpgp@brainhub.org> (wk)
|
||||
|
||||
Integrated ECC support. Below are the changes finally merged into
|
||||
the git master after some cleanup by wk until 2011-02-03.
|
||||
|
||||
* ecdh.c: New.
|
||||
|
||||
* sign.c (mpi_from_sexp): Remove.
|
||||
(match_dsa_hash): Uses SHA-512 for ECDSA with 521 bits.
|
||||
(hash_for): Support ECDSA.
|
||||
(make_keysig_packet): Ditto.
|
||||
|
||||
* seskey.c (encode_session_key): Add arg OPENPGP_PK_ALGO. Support
|
||||
ECDH.
|
||||
(encode_md_value): Map pkalgo. Extend size checks to ECDSA.
|
||||
|
||||
* pubkey-enc.c (get_it): Support ECDH.
|
||||
|
||||
* pkglue.c (mpi_from_sexp): Make global.
|
||||
(pk_verify, pk_encrypt, pk_check_secret_key): Support ECC.
|
||||
|
||||
* parse-packet.c (read_size_body): New.
|
||||
(parse_pubkeyenc): Support ECC.
|
||||
(parse_key): Ditto.
|
||||
|
||||
* misc.c (map_pk_openpgp_to_gcry, map_pk_gcry_to_openpgp): New.
|
||||
(openpgp_pk_test_algo, openpgp_pk_test_algo2): Map algo numbers.
|
||||
(openpgp_pk_algo_usage): Support ECDH and ECDSA.
|
||||
(openpgp_pk_algo_name): Simplify.
|
||||
(ecdsa_qbits_from_Q): New.
|
||||
|
||||
* mainproc.c (proc_pubkey_enc): Support ECC.
|
||||
|
||||
* keyid.c (pubkey_letter): Add 'E' and 'e'.
|
||||
(keygrip_from_pk): Supporf ECC.
|
||||
|
||||
* keygen.c: Include pkglue.h.
|
||||
(ask_algo): Add option 9 for ECDSA and ECDH.
|
||||
(ask_keysize): Support ECDSA and ECDH.
|
||||
(do_create): Ditto.
|
||||
(gen_ecc): New.
|
||||
(pk_ecc_build_key_params): New.
|
||||
|
||||
* getkey.c (cache_public_key): Support ECC.
|
||||
|
||||
* encrypt.c (write_pubkey_enc_from_list): Pass PK to PK_ENCRYPT
|
||||
and the pkalgo to encode_session_key.
|
||||
|
||||
* build-packet.c (do_key, do_pubkey_enc): Support ECC.
|
||||
(write_size_body_mpi): New.
|
||||
|
||||
2011-01-06 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpg.c (main): Use keyserver_spec_t.
|
||||
@ -20,6 +151,12 @@
|
||||
out to ../common/keyserver.h.
|
||||
(keyserver_spec_t): New.
|
||||
|
||||
2011-01-21 Werner Koch <wk@g10code.com>
|
||||
|
||||
* seskey.c (encode_md_value): Truncate the DSA hash again.
|
||||
|
||||
* misc.c (openpgp_pk_algo_name): Always use the gcrypt function.
|
||||
|
||||
2010-12-09 Werner Koch <wk@g10code.com>
|
||||
|
||||
* tdbio.c (tdbio_set_dbname) [W32CE]: Take care of missing errno.
|
||||
|
@ -72,7 +72,8 @@ common_source = \
|
||||
plaintext.c \
|
||||
sig-check.c \
|
||||
keylist.c \
|
||||
pkglue.c pkglue.h
|
||||
pkglue.c pkglue.h \
|
||||
ecdh.c
|
||||
|
||||
gpg2_SOURCES = gpg.c \
|
||||
server.c \
|
||||
@ -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 \
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
454
g10/ecdh.c
Normal file
@ -0,0 +1,454 @@
|
||||
/* ecdh.c - ECDH public key operations used in public key glue code
|
||||
* Copyright (C) 2010, 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "gpg.h"
|
||||
#include "util.h"
|
||||
#include "pkglue.h"
|
||||
#include "main.h"
|
||||
#include "options.h"
|
||||
|
||||
/* A table with the default KEK parameters used by GnuPG. */
|
||||
static const struct
|
||||
{
|
||||
unsigned int qbits;
|
||||
int openpgp_hash_id; /* KEK digest algorithm. */
|
||||
int openpgp_cipher_id; /* KEK cipher algorithm. */
|
||||
} kek_params_table[] =
|
||||
/* Note: Must be sorted by ascending values for QBITS. */
|
||||
{
|
||||
{ 256, DIGEST_ALGO_SHA256, CIPHER_ALGO_AES },
|
||||
{ 384, DIGEST_ALGO_SHA384, CIPHER_ALGO_AES256 },
|
||||
|
||||
/* Note: 528 is 521 rounded to the 8 bit boundary */
|
||||
{ 528, DIGEST_ALGO_SHA512, CIPHER_ALGO_AES256 }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Return KEK parameters as an opaque MPI The caller must free the
|
||||
returned value. Returns NULL and sets ERRNO on error. */
|
||||
gcry_mpi_t
|
||||
pk_ecdh_default_params (unsigned int qbits)
|
||||
{
|
||||
byte *kek_params;
|
||||
int i;
|
||||
|
||||
kek_params = xtrymalloc (4);
|
||||
if (!kek_params)
|
||||
return NULL;
|
||||
kek_params[0] = 3; /* Number of bytes to follow. */
|
||||
kek_params[1] = 1; /* Version for KDF+AESWRAP. */
|
||||
|
||||
/* Search for matching KEK parameter. Defaults to the strongest
|
||||
possible choices. Performance is not an issue here, only
|
||||
interoperability. */
|
||||
for (i=0; i < DIM (kek_params_table); i++)
|
||||
{
|
||||
if (kek_params_table[i].qbits >= qbits
|
||||
|| i+1 == DIM (kek_params_table))
|
||||
{
|
||||
kek_params[2] = kek_params_table[i].openpgp_hash_id;
|
||||
kek_params[3] = kek_params_table[i].openpgp_cipher_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert (i < DIM (kek_params_table));
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ECDH KEK params are", kek_params, sizeof(kek_params) );
|
||||
|
||||
return gcry_mpi_set_opaque (NULL, kek_params, 4 * 8);
|
||||
}
|
||||
|
||||
|
||||
/* Encrypts/decrypts DATA using a key derived from the ECC shared
|
||||
point SHARED_MPI using the FIPS SP 800-56A compliant method
|
||||
key_derivation+key_wrapping. If IS_ENCRYPT is true the function
|
||||
encrypts; if false, it decrypts. On success the result is stored
|
||||
at R_RESULT; on failure NULL is stored at R_RESULT and an error
|
||||
code returned.
|
||||
|
||||
FIXME: explain PKEY and PK_FP.
|
||||
*/
|
||||
|
||||
/*
|
||||
TODO: memory leaks (x_secret).
|
||||
*/
|
||||
gpg_error_t
|
||||
pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
const byte pk_fp[MAX_FINGERPRINT_LEN],
|
||||
gcry_mpi_t data, gcry_mpi_t *pkey,
|
||||
gcry_mpi_t *r_result)
|
||||
{
|
||||
gpg_error_t err;
|
||||
byte *secret_x;
|
||||
int secret_x_size;
|
||||
unsigned int nbits;
|
||||
const unsigned char *kek_params;
|
||||
size_t kek_params_size;
|
||||
int kdf_hash_algo;
|
||||
int kdf_encr_algo;
|
||||
unsigned char message[256];
|
||||
size_t message_size;
|
||||
|
||||
*r_result = NULL;
|
||||
|
||||
nbits = pubkey_nbits (PUBKEY_ALGO_ECDH, pkey);
|
||||
if (!nbits)
|
||||
return gpg_error (GPG_ERR_TOO_SHORT);
|
||||
|
||||
{
|
||||
size_t nbytes;
|
||||
|
||||
/* Extract x component of the shared point: this is the actual
|
||||
shared secret. */
|
||||
nbytes = (mpi_get_nbits (pkey[1] /* public point */)+7)/8;
|
||||
secret_x = xtrymalloc_secure (nbytes);
|
||||
if (!secret_x)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
err = gcry_mpi_print (GCRYMPI_FMT_USG, secret_x, nbytes,
|
||||
&nbytes, shared_mpi);
|
||||
if (err)
|
||||
{
|
||||
xfree (secret_x);
|
||||
log_error ("ECDH ephemeral export of shared point failed: %s\n",
|
||||
gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
secret_x_size = (nbits+7)/8;
|
||||
assert (nbytes > secret_x_size);
|
||||
memmove (secret_x, secret_x+1, secret_x_size);
|
||||
memset (secret_x+secret_x_size, 0, nbytes-secret_x_size);
|
||||
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ECDH shared secret X is:", secret_x, secret_x_size );
|
||||
}
|
||||
|
||||
/*** We have now the shared secret bytes in secret_x. ***/
|
||||
|
||||
/* At this point we are done with PK encryption and the rest of the
|
||||
* function uses symmetric key encryption techniques to protect the
|
||||
* input DATA. The following two sections will simply replace
|
||||
* current secret_x with a value derived from it. This will become
|
||||
* a KEK.
|
||||
*/
|
||||
if (!gcry_mpi_get_flag (pkey[2], GCRYMPI_FLAG_OPAQUE))
|
||||
return GPG_ERR_BUG;
|
||||
kek_params = gcry_mpi_get_opaque (pkey[2], &nbits);
|
||||
kek_params_size = (nbits+7)/8;
|
||||
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ecdh KDF params:", kek_params, kek_params_size);
|
||||
|
||||
/* Expect 4 bytes 03 01 hash_alg symm_alg. */
|
||||
if (kek_params_size != 4 || kek_params[0] != 3 || kek_params[1] != 1)
|
||||
return GPG_ERR_BAD_PUBKEY;
|
||||
|
||||
kdf_hash_algo = kek_params[2];
|
||||
kdf_encr_algo = kek_params[3];
|
||||
|
||||
if (DBG_CIPHER)
|
||||
log_debug ("ecdh KDF algorithms %s+%s with aeswrap\n",
|
||||
openpgp_md_algo_name (kdf_hash_algo),
|
||||
openpgp_cipher_algo_name (kdf_encr_algo));
|
||||
|
||||
if (kdf_hash_algo != GCRY_MD_SHA256
|
||||
&& kdf_hash_algo != GCRY_MD_SHA384
|
||||
&& kdf_hash_algo != GCRY_MD_SHA512)
|
||||
return GPG_ERR_BAD_PUBKEY;
|
||||
if (kdf_encr_algo != GCRY_CIPHER_AES128
|
||||
&& kdf_encr_algo != GCRY_CIPHER_AES192
|
||||
&& kdf_encr_algo != GCRY_CIPHER_AES256)
|
||||
return GPG_ERR_BAD_PUBKEY;
|
||||
|
||||
/* Build kdf_params. */
|
||||
{
|
||||
IOBUF obuf;
|
||||
|
||||
obuf = iobuf_temp();
|
||||
/* variable-length field 1, curve name OID */
|
||||
err = gpg_mpi_write (obuf, pkey[0]);
|
||||
/* fixed-length field 2 */
|
||||
iobuf_put (obuf, PUBKEY_ALGO_ECDH);
|
||||
/* variable-length field 3, KDF params */
|
||||
err = (err ? err : gpg_mpi_write (obuf, pkey[2]));
|
||||
/* fixed-length field 4 */
|
||||
iobuf_write (obuf, "Anonymous Sender ", 20);
|
||||
/* fixed-length field 5, recipient fp */
|
||||
iobuf_write (obuf, pk_fp, 20);
|
||||
|
||||
message_size = iobuf_temp_to_buffer (obuf, message, sizeof message);
|
||||
iobuf_close (obuf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if(DBG_CIPHER)
|
||||
log_printhex ("ecdh KDF message params are:", message, message_size);
|
||||
}
|
||||
|
||||
/* Derive a KEK (key wrapping key) using MESSAGE and SECRET_X. */
|
||||
{
|
||||
gcry_md_hd_t h;
|
||||
int old_size;
|
||||
|
||||
err = gcry_md_open (&h, kdf_hash_algo, 0);
|
||||
if(err)
|
||||
log_bug ("gcry_md_open failed for algo %d: %s",
|
||||
kdf_hash_algo, gpg_strerror (err));
|
||||
gcry_md_write(h, "\x00\x00\x00\x01", 4); /* counter = 1 */
|
||||
gcry_md_write(h, secret_x, secret_x_size); /* x of the point X */
|
||||
gcry_md_write(h, message, message_size);/* KDF parameters */
|
||||
|
||||
gcry_md_final (h);
|
||||
|
||||
assert( gcry_md_get_algo_dlen (kdf_hash_algo) >= 32 );
|
||||
|
||||
memcpy (secret_x, gcry_md_read (h, kdf_hash_algo),
|
||||
gcry_md_get_algo_dlen (kdf_hash_algo));
|
||||
gcry_md_close (h);
|
||||
|
||||
old_size = secret_x_size;
|
||||
assert( old_size >= gcry_cipher_get_algo_keylen( kdf_encr_algo ) );
|
||||
secret_x_size = gcry_cipher_get_algo_keylen( kdf_encr_algo );
|
||||
assert( secret_x_size <= gcry_md_get_algo_dlen (kdf_hash_algo) );
|
||||
|
||||
/* We could have allocated more, so clean the tail before returning. */
|
||||
memset( secret_x+secret_x_size, old_size-secret_x_size, 0 );
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ecdh KEK is:", secret_x, secret_x_size );
|
||||
}
|
||||
|
||||
/* And, finally, aeswrap with key secret_x. */
|
||||
{
|
||||
gcry_cipher_hd_t hd;
|
||||
size_t nbytes;
|
||||
|
||||
byte *data_buf;
|
||||
int data_buf_size;
|
||||
|
||||
gcry_mpi_t result;
|
||||
|
||||
err = gcry_cipher_open (&hd, kdf_encr_algo, GCRY_CIPHER_MODE_AESWRAP, 0);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ecdh failed to initialize AESWRAP: %s\n",
|
||||
gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
err = gcry_cipher_setkey (hd, secret_x, secret_x_size);
|
||||
xfree( secret_x );
|
||||
if (err)
|
||||
{
|
||||
gcry_cipher_close (hd);
|
||||
log_error ("ecdh failed in gcry_cipher_setkey: %s\n",
|
||||
gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
data_buf_size = (gcry_mpi_get_nbits(data)+7)/8;
|
||||
assert ((data_buf_size & 7) == (is_encrypt ? 0 : 1));
|
||||
|
||||
data_buf = xtrymalloc_secure( 1 + 2*data_buf_size + 8);
|
||||
if (!data_buf)
|
||||
{
|
||||
gcry_cipher_close (hd);
|
||||
return GPG_ERR_ENOMEM;
|
||||
}
|
||||
|
||||
if (is_encrypt)
|
||||
{
|
||||
byte *in = data_buf+1+data_buf_size+8;
|
||||
|
||||
/* Write data MPI into the end of data_buf. data_buf is size
|
||||
aeswrap data. */
|
||||
err = gcry_mpi_print (GCRYMPI_FMT_USG, in,
|
||||
data_buf_size, &nbytes, data/*in*/);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ecdh failed to export DEK: %s\n", gpg_strerror (err));
|
||||
gcry_cipher_close (hd);
|
||||
xfree (data_buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ecdh encrypting :", in, data_buf_size );
|
||||
|
||||
err = gcry_cipher_encrypt (hd, data_buf+1, data_buf_size+8,
|
||||
in, data_buf_size);
|
||||
memset (in, 0, data_buf_size);
|
||||
gcry_cipher_close (hd);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ecdh failed in gcry_cipher_encrypt: %s\n",
|
||||
gpg_strerror (err));
|
||||
xfree (data_buf);
|
||||
return err;
|
||||
}
|
||||
data_buf[0] = data_buf_size+8;
|
||||
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ecdh encrypted to:", data_buf+1, data_buf[0] );
|
||||
|
||||
result = gcry_mpi_set_opaque (NULL, data_buf, 8 * (1+data_buf[0]));
|
||||
if (!result)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
xfree (data_buf);
|
||||
log_error ("ecdh failed to create an MPI: %s\n",
|
||||
gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
*r_result = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte *in;
|
||||
const void *p;
|
||||
|
||||
p = gcry_mpi_get_opaque (data, &nbits);
|
||||
nbytes = (nbits+7)/8;
|
||||
if (!p || nbytes > data_buf_size || !nbytes)
|
||||
{
|
||||
xfree (data_buf);
|
||||
return GPG_ERR_BAD_MPI;
|
||||
}
|
||||
memcpy (data_buf, p, nbytes);
|
||||
if (data_buf[0] != nbytes-1)
|
||||
{
|
||||
log_error ("ecdh inconsistent size\n");
|
||||
xfree (data_buf);
|
||||
return GPG_ERR_BAD_MPI;
|
||||
}
|
||||
in = data_buf+data_buf_size;
|
||||
data_buf_size = data_buf[0];
|
||||
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ecdh decrypting :", data_buf+1, data_buf_size);
|
||||
|
||||
err = gcry_cipher_decrypt (hd, in, data_buf_size, data_buf+1,
|
||||
data_buf_size);
|
||||
gcry_cipher_close (hd);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ecdh failed in gcry_cipher_decrypt: %s\n",
|
||||
gpg_strerror (err));
|
||||
xfree (data_buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
data_buf_size -= 8;
|
||||
|
||||
if (DBG_CIPHER)
|
||||
log_printhex ("ecdh decrypted to :", in, data_buf_size);
|
||||
|
||||
/* Padding is removed later. */
|
||||
/* if (in[data_buf_size-1] > 8 ) */
|
||||
/* { */
|
||||
/* log_error("ecdh failed at decryption: invalid padding. %02x > 8\n", */
|
||||
/* in[data_buf_size-1] ); */
|
||||
/* return GPG_ERR_BAD_KEY; */
|
||||
/* } */
|
||||
|
||||
err = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, in, data_buf_size, NULL);
|
||||
xfree (data_buf);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ecdh failed to create a plain text MPI: %s\n",
|
||||
gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
*r_result = result;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static gcry_mpi_t
|
||||
gen_k (unsigned nbits)
|
||||
{
|
||||
gcry_mpi_t k;
|
||||
|
||||
k = gcry_mpi_snew (nbits);
|
||||
if (DBG_CIPHER)
|
||||
log_debug ("choosing a random k of %u bits\n", nbits);
|
||||
|
||||
gcry_mpi_randomize (k, nbits-1, GCRY_STRONG_RANDOM);
|
||||
|
||||
if (DBG_CIPHER)
|
||||
{
|
||||
unsigned char *buffer;
|
||||
if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, k))
|
||||
BUG ();
|
||||
log_debug ("ephemeral scalar MPI #0: %s\n", buffer);
|
||||
gcry_free (buffer);
|
||||
}
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
/* Generate an ephemeral key for the public ECDH key in PKEY. On
|
||||
success the generated key is stored at R_K; on failure NULL is
|
||||
stored at R_K and an error code returned. */
|
||||
gpg_error_t
|
||||
pk_ecdh_generate_ephemeral_key (gcry_mpi_t *pkey, gcry_mpi_t *r_k)
|
||||
{
|
||||
unsigned int nbits;
|
||||
gcry_mpi_t k;
|
||||
|
||||
*r_k = NULL;
|
||||
|
||||
nbits = pubkey_nbits (PUBKEY_ALGO_ECDH, pkey);
|
||||
if (!nbits)
|
||||
return gpg_error (GPG_ERR_TOO_SHORT);
|
||||
k = gen_k (nbits);
|
||||
if (!k)
|
||||
BUG ();
|
||||
|
||||
*r_k = k;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Perform ECDH decryption. */
|
||||
int
|
||||
pk_ecdh_decrypt (gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN],
|
||||
gcry_mpi_t data, gcry_mpi_t shared, gcry_mpi_t * skey)
|
||||
{
|
||||
if (!data)
|
||||
return gpg_error (GPG_ERR_BAD_MPI);
|
||||
return pk_ecdh_encrypt_with_shared_point (0 /*=decryption*/, shared,
|
||||
sk_fp, data/*encr data as an MPI*/,
|
||||
skey, result);
|
||||
}
|
128
g10/encrypt.c
128
g10/encrypt.c
@ -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];
|
||||
|
158
g10/export.c
158
g10/export.c
@ -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;
|
||||
|
@ -138,7 +138,10 @@ cache_public_key (PKT_public_key * pk)
|
||||
return;
|
||||
|
||||
if (is_ELGAMAL (pk->pubkey_algo)
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_DSA || is_RSA (pk->pubkey_algo))
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_DSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH
|
||||
|| is_RSA (pk->pubkey_algo))
|
||||
{
|
||||
keyid_from_pk (pk, keyid);
|
||||
}
|
||||
|
@ -858,7 +858,7 @@ my_strusage( int level )
|
||||
case 34:
|
||||
if (!pubkeys)
|
||||
pubkeys = build_list (_("Pubkey: "), 0,
|
||||
gcry_pk_algo_name,
|
||||
openpgp_pk_algo_name,
|
||||
openpgp_pk_test_algo );
|
||||
p = pubkeys;
|
||||
break;
|
||||
@ -1959,6 +1959,9 @@ main (int argc, char **argv)
|
||||
NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
|
||||
}
|
||||
|
||||
/* Use our own logging handler for Libcgrypt. */
|
||||
setup_libgcrypt_logging ();
|
||||
|
||||
/* Put random number into secure memory */
|
||||
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
|
||||
|
||||
|
252
g10/import.c
252
g10/import.c
@ -1,6 +1,6 @@
|
||||
/* import.c - import a key into our key storage.
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
||||
* 2007, 2010 Free Software Foundation, Inc.
|
||||
* 2007, 2010, 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -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;
|
||||
}
|
||||
|
490
g10/keygen.c
490
g10/keygen.c
File diff suppressed because it is too large
Load Diff
111
g10/keyid.c
111
g10/keyid.c
@ -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;
|
||||
}
|
||||
|
||||
|
24
g10/main.h
24
g10/main.h
@ -87,17 +87,22 @@ u16 checksum_mpi( gcry_mpi_t a );
|
||||
u32 buffer_to_u32( const byte *buffer );
|
||||
const byte *get_session_marker( size_t *rlen );
|
||||
int map_cipher_openpgp_to_gcry (int algo);
|
||||
#define openpgp_cipher_open(_a,_b,_c,_d) gcry_cipher_open((_a),map_cipher_openpgp_to_gcry((_b)),(_c),(_d))
|
||||
#define openpgp_cipher_get_algo_keylen(_a) gcry_cipher_get_algo_keylen(map_cipher_openpgp_to_gcry((_a)))
|
||||
#define openpgp_cipher_get_algo_blklen(_a) gcry_cipher_get_algo_blklen(map_cipher_openpgp_to_gcry((_a)))
|
||||
#define openpgp_cipher_open(_a,_b,_c,_d) \
|
||||
gcry_cipher_open((_a),map_cipher_openpgp_to_gcry((_b)),(_c),(_d))
|
||||
#define openpgp_cipher_get_algo_keylen(_a) \
|
||||
gcry_cipher_get_algo_keylen(map_cipher_openpgp_to_gcry((_a)))
|
||||
#define openpgp_cipher_get_algo_blklen(_a) \
|
||||
gcry_cipher_get_algo_blklen(map_cipher_openpgp_to_gcry((_a)))
|
||||
int openpgp_cipher_blocklen (int algo);
|
||||
int openpgp_cipher_test_algo( int algo );
|
||||
const char *openpgp_cipher_algo_name (int algo);
|
||||
int map_pk_openpgp_to_gcry (int algo);
|
||||
int map_pk_gcry_to_openpgp (enum gcry_pk_algos algo);
|
||||
int openpgp_pk_test_algo( int algo );
|
||||
int openpgp_pk_test_algo2 ( int algo, unsigned int use );
|
||||
int openpgp_pk_algo_usage ( int algo );
|
||||
const char *openpgp_pk_algo_name (int algo);
|
||||
int openpgp_md_test_algo( int algo );
|
||||
const char *openpgp_pk_algo_name (int algo);
|
||||
const char *openpgp_md_algo_name (int algo);
|
||||
|
||||
#ifdef USE_IDEA
|
||||
@ -150,13 +155,16 @@ int is_valid_mailbox (const char *name);
|
||||
const char *get_libexecdir (void);
|
||||
int path_access(const char *file,int mode);
|
||||
|
||||
/* Temporary helpers. */
|
||||
int pubkey_get_npkey( int algo );
|
||||
int pubkey_get_nskey( int algo );
|
||||
int pubkey_get_nsig( int algo );
|
||||
int pubkey_get_nenc( int algo );
|
||||
|
||||
/* Temporary helpers. */
|
||||
unsigned int pubkey_nbits( int algo, gcry_mpi_t *pkey );
|
||||
int mpi_print (estream_t stream, gcry_mpi_t a, int mode);
|
||||
unsigned int ecdsa_qbits_from_Q (unsigned int qbits);
|
||||
|
||||
|
||||
/*-- status.c --*/
|
||||
void set_status_fd ( int fd );
|
||||
@ -228,6 +236,7 @@ void keyedit_passwd (ctrl_t ctrl, const char *username);
|
||||
void show_basic_key_info (KBNODE keyblock);
|
||||
|
||||
/*-- keygen.c --*/
|
||||
const char *gpg_curve_to_oid (const char *name, unsigned int *r_nbits);
|
||||
u32 parse_expire_string(const char *string);
|
||||
u32 ask_expire_interval(int object,const char *def_expire);
|
||||
u32 ask_expiredate(void);
|
||||
@ -251,6 +260,7 @@ gpg_error_t generate_card_subkeypair (kbnode_t pub_keyblock,
|
||||
int save_unprotected_key_to_card (PKT_public_key *sk, int keyno);
|
||||
#endif
|
||||
|
||||
|
||||
/*-- openfile.c --*/
|
||||
int overwrite_filep( const char *fname );
|
||||
char *make_outfile_name( const char *iname );
|
||||
@ -261,7 +271,7 @@ void try_make_homedir( const char *fname );
|
||||
|
||||
/*-- seskey.c --*/
|
||||
void make_session_key( DEK *dek );
|
||||
gcry_mpi_t encode_session_key( DEK *dek, unsigned nbits );
|
||||
gcry_mpi_t encode_session_key( int openpgp_pk_algo, DEK *dek, unsigned nbits );
|
||||
gcry_mpi_t encode_md_value (PKT_public_key *pk,
|
||||
gcry_md_hd_t md, int hash_algo );
|
||||
|
||||
@ -294,7 +304,7 @@ gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec,
|
||||
int export_seckeys (ctrl_t ctrl, strlist_t users);
|
||||
int export_secsubkeys (ctrl_t ctrl, strlist_t users);
|
||||
|
||||
/* dearmor.c --*/
|
||||
/*-- dearmor.c --*/
|
||||
int dearmor_file( const char *fname );
|
||||
int enarmor_file( const char *fname );
|
||||
|
||||
|
@ -384,6 +384,8 @@ proc_pubkey_enc( CTX c, PACKET *pkt )
|
||||
}
|
||||
else if( is_ELGAMAL(enc->pubkey_algo)
|
||||
|| enc->pubkey_algo == PUBKEY_ALGO_DSA
|
||||
|| enc->pubkey_algo == PUBKEY_ALGO_ECDSA
|
||||
|| enc->pubkey_algo == PUBKEY_ALGO_ECDH
|
||||
|| is_RSA(enc->pubkey_algo)
|
||||
|| enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL) {
|
||||
/* Note that we also allow type 20 Elgamal keys for decryption.
|
||||
@ -450,7 +452,7 @@ print_pkenc_list( struct kidlist_item *list, int failed )
|
||||
if ( !failed && list->reason )
|
||||
continue;
|
||||
|
||||
algstr = gcry_pk_algo_name ( list->pubkey_algo );
|
||||
algstr = openpgp_pk_algo_name ( list->pubkey_algo );
|
||||
pk = xmalloc_clear( sizeof *pk );
|
||||
|
||||
if( !algstr )
|
||||
@ -1616,7 +1618,7 @@ check_sig_and_print( CTX c, KBNODE node )
|
||||
|
||||
/* (Indendation below not yet changed to GNU style.) */
|
||||
|
||||
astr = gcry_pk_algo_name ( sig->pubkey_algo );
|
||||
astr = openpgp_pk_algo_name ( sig->pubkey_algo );
|
||||
if(keystrlen()>8)
|
||||
{
|
||||
log_info(_("Signature made %s\n"),asctimestamp(sig->timestamp));
|
||||
|
147
g10/misc.c
147
g10/misc.c
@ -1,6 +1,6 @@
|
||||
/* misc.c - miscellaneous functions
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
* 2008, 2009 Free Software Foundation, Inc.
|
||||
* 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -64,6 +64,7 @@
|
||||
#include "call-agent.h"
|
||||
#include "i18n.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static int
|
||||
string_count_chr (const char *string, int c)
|
||||
@ -294,7 +295,7 @@ print_pubkey_algo_note( int algo )
|
||||
{
|
||||
warn=1;
|
||||
log_info (_("WARNING: using experimental public key algorithm %s\n"),
|
||||
gcry_pk_algo_name (algo));
|
||||
openpgp_cipher_algo_name (algo));
|
||||
}
|
||||
}
|
||||
else if (algo == 20)
|
||||
@ -365,6 +366,32 @@ map_cipher_gcry_to_openpgp (int algo)
|
||||
}
|
||||
}
|
||||
|
||||
/* Map OpenPGP public key algorithm numbers to those used by
|
||||
Libgcrypt. */
|
||||
int
|
||||
map_pk_openpgp_to_gcry (int algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case PUBKEY_ALGO_ECDSA: return GCRY_PK_ECDSA;
|
||||
case PUBKEY_ALGO_ECDH: return GCRY_PK_ECDH;
|
||||
default: return algo;
|
||||
}
|
||||
}
|
||||
|
||||
/* Map Gcrypt public key algorithm numbers to those used by
|
||||
OpenPGP. */
|
||||
int
|
||||
map_pk_gcry_to_openpgp (enum gcry_pk_algos algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA;
|
||||
case GCRY_PK_ECDH: return PUBKEY_ALGO_ECDH;
|
||||
default: return algo < 110 ? algo : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return the block length of an OpenPGP cipher algorithm. */
|
||||
int
|
||||
@ -424,7 +451,8 @@ openpgp_pk_test_algo( int algo )
|
||||
|
||||
if (algo < 0 || algo > 110)
|
||||
return gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
return gcry_pk_test_algo (algo);
|
||||
|
||||
return gcry_pk_test_algo (map_pk_openpgp_to_gcry (algo));
|
||||
}
|
||||
|
||||
int
|
||||
@ -442,7 +470,8 @@ openpgp_pk_test_algo2( int algo, unsigned int use )
|
||||
if (algo < 0 || algo > 110)
|
||||
return gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
|
||||
return gcry_pk_algo_info (algo, GCRYCTL_TEST_ALGO, NULL, &use_buf);
|
||||
return gcry_pk_algo_info (map_pk_openpgp_to_gcry (algo),
|
||||
GCRYCTL_TEST_ALGO, NULL, &use_buf);
|
||||
}
|
||||
|
||||
int
|
||||
@ -457,6 +486,7 @@ openpgp_pk_algo_usage ( int algo )
|
||||
| PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH);
|
||||
break;
|
||||
case PUBKEY_ALGO_RSA_E:
|
||||
case PUBKEY_ALGO_ECDH:
|
||||
use = PUBKEY_USAGE_ENC;
|
||||
break;
|
||||
case PUBKEY_ALGO_RSA_S:
|
||||
@ -472,6 +502,8 @@ openpgp_pk_algo_usage ( int algo )
|
||||
case PUBKEY_ALGO_DSA:
|
||||
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
|
||||
break;
|
||||
case PUBKEY_ALGO_ECDSA:
|
||||
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -484,19 +516,7 @@ openpgp_pk_algo_usage ( int algo )
|
||||
const char *
|
||||
openpgp_pk_algo_name (int algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case PUBKEY_ALGO_RSA:
|
||||
case PUBKEY_ALGO_RSA_E:
|
||||
case PUBKEY_ALGO_RSA_S: return "rsa";
|
||||
|
||||
case PUBKEY_ALGO_ELGAMAL:
|
||||
case PUBKEY_ALGO_ELGAMAL_E: return "elg";
|
||||
|
||||
case PUBKEY_ALGO_DSA: return "dsa";
|
||||
|
||||
default: return "?";
|
||||
}
|
||||
return gcry_pk_algo_name (map_pk_openpgp_to_gcry (algo));
|
||||
}
|
||||
|
||||
|
||||
@ -1340,27 +1360,44 @@ path_access(const char *file,int mode)
|
||||
|
||||
|
||||
|
||||
/* Temporary helper. */
|
||||
/* Return the number of public key parameters as used by OpenPGP. */
|
||||
int
|
||||
pubkey_get_npkey( int algo )
|
||||
pubkey_get_npkey (int algo)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
/* ECC is special. */
|
||||
if (algo == PUBKEY_ALGO_ECDSA)
|
||||
return 2;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
return 3;
|
||||
|
||||
/* All other algorithms match those of Libgcrypt. */
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &n))
|
||||
|
||||
if (gcry_pk_algo_info (algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &n))
|
||||
n = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Temporary helper. */
|
||||
|
||||
/* Return the number of secret key parameters as used by OpenPGP. */
|
||||
int
|
||||
pubkey_get_nskey( int algo )
|
||||
pubkey_get_nskey (int algo)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
/* ECC is special. */
|
||||
if (algo == PUBKEY_ALGO_ECDSA)
|
||||
return 3;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
return 4;
|
||||
|
||||
/* All other algorithms match those of Libgcrypt. */
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
|
||||
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &n ))
|
||||
n = 0;
|
||||
return n;
|
||||
@ -1368,25 +1405,40 @@ pubkey_get_nskey( int algo )
|
||||
|
||||
/* Temporary helper. */
|
||||
int
|
||||
pubkey_get_nsig( int algo )
|
||||
pubkey_get_nsig (int algo)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
/* ECC is special. */
|
||||
if (algo == PUBKEY_ALGO_ECDSA)
|
||||
return 2;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
return 0;
|
||||
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
|
||||
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSIGN, NULL, &n))
|
||||
n = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/* Temporary helper. */
|
||||
int
|
||||
pubkey_get_nenc( int algo )
|
||||
pubkey_get_nenc (int algo)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
/* ECC is special. */
|
||||
if (algo == PUBKEY_ALGO_ECDSA)
|
||||
return 0;
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
return 2;
|
||||
|
||||
if (algo == GCRY_PK_ELG_E)
|
||||
algo = GCRY_PK_ELG;
|
||||
|
||||
if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NENCR, NULL, &n ))
|
||||
n = 0;
|
||||
return n;
|
||||
@ -1400,6 +1452,9 @@ pubkey_nbits( int algo, gcry_mpi_t *key )
|
||||
int rc, nbits;
|
||||
gcry_sexp_t sexp;
|
||||
|
||||
#warning FIXME: We are mixing OpenPGP And CGrypt Ids
|
||||
assert( algo != GCRY_PK_ECDSA && algo != GCRY_PK_ECDH );
|
||||
|
||||
if( algo == GCRY_PK_DSA ) {
|
||||
rc = gcry_sexp_build ( &sexp, NULL,
|
||||
"(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
|
||||
@ -1415,6 +1470,18 @@ pubkey_nbits( int algo, gcry_mpi_t *key )
|
||||
"(public-key(rsa(n%m)(e%m)))",
|
||||
key[0], key[1] );
|
||||
}
|
||||
else if( algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH ) {
|
||||
char *curve = openpgp_oid_to_str (key[0]);
|
||||
if (!curve)
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
rc = gcry_sexp_build (&sexp, NULL,
|
||||
"(public-key(ecc(curve%s)(q%m)))",
|
||||
curve, key[1]);
|
||||
xfree (curve);
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
@ -1428,7 +1495,6 @@ pubkey_nbits( int algo, gcry_mpi_t *key )
|
||||
|
||||
|
||||
|
||||
/* FIXME: Use gcry_mpi_print directly. */
|
||||
int
|
||||
mpi_print (estream_t fp, gcry_mpi_t a, int mode)
|
||||
{
|
||||
@ -1442,6 +1508,19 @@ mpi_print (estream_t fp, gcry_mpi_t a, int mode)
|
||||
n1 = gcry_mpi_get_nbits(a);
|
||||
n += es_fprintf (fp, "[%u bits]", n1);
|
||||
}
|
||||
else if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
unsigned int nbits;
|
||||
unsigned char *p = gcry_mpi_get_opaque (a, &nbits);
|
||||
if (!p)
|
||||
n += es_fprintf (fp, "[invalid opaque value]");
|
||||
else
|
||||
{
|
||||
nbits = (nbits + 7)/8;
|
||||
for (; nbits; nbits--, p++)
|
||||
n += es_fprintf (fp, "%02X", *p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char *buffer;
|
||||
@ -1455,3 +1534,21 @@ mpi_print (estream_t fp, gcry_mpi_t a, int mode)
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/* pkey[1] or skey[1] is Q for ECDSA, which is an uncompressed point,
|
||||
i.e. 04 <x> <y> */
|
||||
unsigned int
|
||||
ecdsa_qbits_from_Q (unsigned int qbits)
|
||||
{
|
||||
if ((qbits%8) > 3)
|
||||
{
|
||||
log_error (_("ECDSA public key is expected to be in SEC encoding "
|
||||
"multiple of 8 bits\n"));
|
||||
return 0;
|
||||
}
|
||||
qbits -= qbits%8;
|
||||
qbits /= 2;
|
||||
return qbits;
|
||||
}
|
||||
|
||||
|
||||
|
@ -444,6 +444,7 @@ PACKET *create_gpg_control ( ctrlpkttype_t type,
|
||||
|
||||
/*-- build-packet.c --*/
|
||||
int build_packet( iobuf_t inp, PACKET *pkt );
|
||||
gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a);
|
||||
u32 calc_packet_length( PACKET *pkt );
|
||||
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
|
||||
const byte *buffer, size_t buflen );
|
||||
|
@ -741,6 +741,61 @@ read_rest (IOBUF inp, size_t pktlen, int partial)
|
||||
}
|
||||
|
||||
|
||||
/* Read a special size+body from INP. On success store an opaque MPI
|
||||
with it at R_DATA. On error return an error code and store NULL at
|
||||
R_DATA. Even in the error case store the number of read bytes at
|
||||
R_NREAD. The caller shall pass the remaining size of the packet in
|
||||
PKTLEN. */
|
||||
static gpg_error_t
|
||||
read_size_body (iobuf_t inp, int pktlen, size_t *r_nread,
|
||||
gcry_mpi_t *r_data)
|
||||
{
|
||||
char buffer[256];
|
||||
char *tmpbuf;
|
||||
int i, c, nbytes;
|
||||
|
||||
*r_nread = 0;
|
||||
*r_data = NULL;
|
||||
|
||||
if (!pktlen)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
c = iobuf_readbyte (inp);
|
||||
if (c < 0)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
pktlen--;
|
||||
++*r_nread;
|
||||
nbytes = c;
|
||||
if (nbytes < 2 || nbytes > 254)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
if (nbytes > pktlen)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
|
||||
buffer[0] = nbytes;
|
||||
|
||||
for (i = 0; i < nbytes; i++)
|
||||
{
|
||||
c = iobuf_get (inp);
|
||||
if (c < 0)
|
||||
return gpg_error (GPG_ERR_INV_PACKET);
|
||||
++*r_nread;
|
||||
buffer[1+i] = c;
|
||||
}
|
||||
|
||||
tmpbuf = xtrymalloc (1 + nbytes);
|
||||
if (!tmpbuf)
|
||||
return gpg_error_from_syserror ();
|
||||
memcpy (tmpbuf, buffer, 1 + nbytes);
|
||||
*r_data = gcry_mpi_set_opaque (NULL, tmpbuf, 8 * (1 + nbytes));
|
||||
if (!*r_data)
|
||||
{
|
||||
xfree (tmpbuf);
|
||||
return gpg_error_from_syserror ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Parse a marker packet. */
|
||||
static int
|
||||
parse_marker (IOBUF inp, int pkttype, unsigned long pktlen)
|
||||
{
|
||||
@ -940,19 +995,29 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
else
|
||||
{
|
||||
for (i = 0; i < ndata; i++)
|
||||
{
|
||||
n = pktlen;
|
||||
k->data[i] = mpi_read (inp, &n, 0);
|
||||
pktlen -= n;
|
||||
if (list_mode)
|
||||
{
|
||||
es_fprintf (listfp, "\tdata: ");
|
||||
mpi_print (listfp, k->data[i], mpi_print_mode);
|
||||
es_putc ('\n', listfp);
|
||||
}
|
||||
if (!k->data[i])
|
||||
rc = gpg_error (GPG_ERR_INV_PACKET);
|
||||
}
|
||||
{
|
||||
if (k->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
|
||||
{
|
||||
rc = read_size_body (inp, pktlen, &n, k->data+i);
|
||||
pktlen -= n;
|
||||
}
|
||||
else
|
||||
{
|
||||
n = pktlen;
|
||||
k->data[i] = mpi_read (inp, &n, 0);
|
||||
pktlen -= n;
|
||||
if (!k->data[i])
|
||||
rc = gpg_error (GPG_ERR_INV_PACKET);
|
||||
}
|
||||
if (rc)
|
||||
goto leave;
|
||||
if (list_mode)
|
||||
{
|
||||
es_fprintf (listfp, "\tdata: ");
|
||||
mpi_print (listfp, k->data[i], mpi_print_mode);
|
||||
es_putc ('\n', listfp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
@ -1913,7 +1978,6 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
unknown_pubkey_warning (algorithm);
|
||||
}
|
||||
|
||||
|
||||
if (!npkey)
|
||||
{
|
||||
/* Unknown algorithm - put data into an opaque MPI. */
|
||||
@ -1925,25 +1989,32 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Fill in public key parameters. */
|
||||
for (i = 0; i < npkey; i++)
|
||||
{
|
||||
n = pktlen;
|
||||
pk->pkey[i] = mpi_read (inp, &n, 0);
|
||||
pktlen -= n;
|
||||
if (list_mode)
|
||||
{
|
||||
es_fprintf (listfp, "\tpkey[%d]: ", i);
|
||||
mpi_print (listfp, pk->pkey[i], mpi_print_mode);
|
||||
es_putc ('\n', listfp);
|
||||
}
|
||||
if (!pk->pkey[i])
|
||||
err = gpg_error (GPG_ERR_INV_PACKET);
|
||||
}
|
||||
if (err)
|
||||
goto leave;
|
||||
{
|
||||
if ((algorithm == PUBKEY_ALGO_ECDSA
|
||||
|| algorithm == PUBKEY_ALGO_ECDH) && (i==0 || i == 2))
|
||||
{
|
||||
err = read_size_body (inp, pktlen, &n, pk->pkey+i);
|
||||
pktlen -= n;
|
||||
}
|
||||
else
|
||||
{
|
||||
n = pktlen;
|
||||
pk->pkey[i] = mpi_read (inp, &n, 0);
|
||||
pktlen -= n;
|
||||
if (!pk->pkey[i])
|
||||
err = gpg_error (GPG_ERR_INV_PACKET);
|
||||
}
|
||||
if (err)
|
||||
goto leave;
|
||||
if (list_mode)
|
||||
{
|
||||
es_fprintf (listfp, "\tpkey[%d]: ", i);
|
||||
mpi_print (listfp, pk->pkey[i], mpi_print_mode);
|
||||
es_putc ('\n', listfp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (list_mode)
|
||||
keyid_from_pk (pk, keyid);
|
||||
|
||||
|
110
g10/passphrase.c
110
g10/passphrase.c
@ -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;
|
||||
}
|
||||
|
||||
|
219
g10/pkglue.c
219
g10/pkglue.c
@ -1,5 +1,5 @@
|
||||
/* pkglue.c - public key operations glue code
|
||||
* Copyright (C) 2000, 2003 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2000, 2003, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -27,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;
|
||||
}
|
||||
|
||||
|
26
g10/pkglue.h
26
g10/pkglue.h
@ -1,5 +1,5 @@
|
||||
/* pkglue.h - public key operations definitions
|
||||
* Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2003, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -20,13 +20,31 @@
|
||||
#ifndef GNUPG_G10_PKGLUE_H
|
||||
#define GNUPG_G10_PKGLUE_H
|
||||
|
||||
#include "packet.h" /* For PKT_public_key. */
|
||||
|
||||
/*-- pkglue.c --*/
|
||||
gcry_mpi_t mpi_from_sexp (gcry_sexp_t sexp, const char * item);
|
||||
|
||||
int pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data,
|
||||
gcry_mpi_t *pkey);
|
||||
int pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
|
||||
gcry_mpi_t *pkey);
|
||||
int pk_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
|
||||
gcry_mpi_t *skey);
|
||||
PKT_public_key *pk, gcry_mpi_t *pkey);
|
||||
int pk_check_secret_key (int algo, gcry_mpi_t *skey);
|
||||
|
||||
|
||||
/*-- ecdh.c --*/
|
||||
gcry_mpi_t pk_ecdh_default_params (unsigned int qbits);
|
||||
gpg_error_t pk_ecdh_generate_ephemeral_key (gcry_mpi_t *pkey, gcry_mpi_t *r_k);
|
||||
gpg_error_t pk_ecdh_encrypt_with_shared_point
|
||||
/* */ (int is_encrypt, gcry_mpi_t shared_mpi,
|
||||
const byte pk_fp[MAX_FINGERPRINT_LEN],
|
||||
gcry_mpi_t data, gcry_mpi_t *pkey,
|
||||
gcry_mpi_t *out);
|
||||
|
||||
int pk_ecdh_encrypt (gcry_mpi_t *resarr, const byte pk_fp[MAX_FINGERPRINT_LEN],
|
||||
gcry_mpi_t data, gcry_mpi_t * pkey);
|
||||
int pk_ecdh_decrypt (gcry_mpi_t *result, const byte sk_fp[MAX_FINGERPRINT_LEN],
|
||||
gcry_mpi_t data, gcry_mpi_t shared, gcry_mpi_t * skey);
|
||||
|
||||
|
||||
#endif /*GNUPG_G10_PKGLUE_H*/
|
||||
|
@ -145,6 +145,9 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
|
||||
gcry_sexp_t s_data;
|
||||
char *desc;
|
||||
char *keygrip;
|
||||
byte fp[MAX_FINGERPRINT_LEN];
|
||||
size_t fpn;
|
||||
const int pkalgo = map_pk_openpgp_to_gcry (sk->pubkey_algo);
|
||||
|
||||
/* Get the keygrip. */
|
||||
err = hexkeygrip_from_pk (sk, &keygrip);
|
||||
@ -152,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;
|
||||
}
|
||||
|
||||
|
238
g10/seskey.c
238
g10/seskey.c
@ -1,6 +1,6 @@
|
||||
/* seskey.c - make sesssion keys etc.
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
* 2006, 2009 Free Software Foundation, Inc.
|
||||
* 2006, 2009, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -27,6 +27,7 @@
|
||||
#include "gpg.h"
|
||||
#include "util.h"
|
||||
#include "cipher.h"
|
||||
#include "options.h"
|
||||
#include "main.h"
|
||||
#include "i18n.h"
|
||||
|
||||
@ -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();
|
||||
|
44
g10/sign.c
44
g10/sign.c
@ -227,21 +227,6 @@ hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static gcry_mpi_t
|
||||
mpi_from_sexp (gcry_sexp_t sexp, const char * item)
|
||||
{
|
||||
gcry_sexp_t list;
|
||||
gcry_mpi_t data;
|
||||
|
||||
list = gcry_sexp_find_token (sexp, item, 0);
|
||||
assert (list);
|
||||
data = gcry_sexp_nth_mpi (list, 1, 0);
|
||||
assert (data);
|
||||
gcry_sexp_release (list);
|
||||
return data;
|
||||
}
|
||||
|
||||
/* Perform the sign operation. If CACHE_NONCE is given the agent is
|
||||
advised to use that cached passphrase fro the key. */
|
||||
static int
|
||||
@ -418,7 +403,7 @@ match_dsa_hash (unsigned int qbytes)
|
||||
if (qbytes <= 48)
|
||||
return DIGEST_ALGO_SHA384;
|
||||
|
||||
if (qbytes <= 64)
|
||||
if (qbytes <= 66 ) /* 66 corresponds to 521 (64 to 512) */
|
||||
return DIGEST_ALGO_SHA512;
|
||||
|
||||
return DEFAULT_DIGEST_ALGO;
|
||||
@ -451,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;
|
||||
}
|
||||
|
@ -176,5 +176,5 @@ next_tuple (tupledesc_t tupledesc, unsigned int *r_tag, size_t *r_length)
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,5 @@ const void *next_tuple (tupledesc_t tupledesc,
|
||||
unsigned int *r_tag, size_t *r_length);
|
||||
|
||||
|
||||
|
||||
#endif /*G13_UTILS_H*/
|
||||
|
||||
|
@ -1,3 +1,14 @@
|
||||
2011-02-01 Werner Koch <wk@g10code.com>
|
||||
|
||||
* cipher.h (PUBKEY_MAX_NPKEY, PUBKEY_MAX_NSKEY): Bump up to
|
||||
accommodate gcrypt ECC keys.
|
||||
|
||||
2011-01-21 Werner Koch <wk@g10code.com>
|
||||
|
||||
* cipher.h (GCRY_PK_USAGE_CERT): Remove compatibility macros
|
||||
because we now require libgcrypt 1.4.6.
|
||||
(GCRY_PK_ECDH): Add replacement.
|
||||
|
||||
2009-08-20 Daiki Ueno <ueno@unixuser.org> (wk)
|
||||
|
||||
* cipher.h (struct DEK): Add field S2K_CACHEID.
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* cipher.h - Definitions for OpenPGP
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2006,
|
||||
* 2007 Free Software Foundation, Inc.
|
||||
* 2007, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -23,10 +23,8 @@
|
||||
#include <gcrypt.h>
|
||||
|
||||
/* Macros for compatibility with older libgcrypt versions. */
|
||||
#ifndef GCRY_PK_USAGE_CERT
|
||||
# define GCRY_PK_USAGE_CERT 4
|
||||
# define GCRY_PK_USAGE_AUTH 8
|
||||
# define GCRY_PK_USAGE_UNKN 128
|
||||
#ifndef HAVE_GCRY_PK_ECDH
|
||||
# define GCRY_PK_ECDH 302
|
||||
#endif
|
||||
|
||||
|
||||
@ -56,6 +54,8 @@
|
||||
#define PUBKEY_ALGO_RSA_S /* 3 */ GCRY_PK_RSA_S /* RSA sign only. */
|
||||
#define PUBKEY_ALGO_ELGAMAL_E /* 16 */ GCRY_PK_ELG_E /* Elgamal encr only */
|
||||
#define PUBKEY_ALGO_DSA /* 17 */ GCRY_PK_DSA
|
||||
#define PUBKEY_ALGO_ECDH 18
|
||||
#define PUBKEY_ALGO_ECDSA 19
|
||||
#define PUBKEY_ALGO_ELGAMAL /* 20 */ GCRY_PK_ELG /* Elgamal encr+sign */
|
||||
|
||||
#define PUBKEY_USAGE_SIG GCRY_PK_USAGE_SIGN /* Good for signatures. */
|
||||
@ -100,8 +100,8 @@ typedef struct
|
||||
|
||||
|
||||
/* Constants to allocate static MPI arrays. */
|
||||
#define PUBKEY_MAX_NPKEY 4
|
||||
#define PUBKEY_MAX_NSKEY 6
|
||||
#define PUBKEY_MAX_NPKEY 5
|
||||
#define PUBKEY_MAX_NSKEY 7
|
||||
#define PUBKEY_MAX_NSIG 2
|
||||
#define PUBKEY_MAX_NENC 2
|
||||
|
||||
|
@ -186,7 +186,7 @@ next_packet (unsigned char const **bufptr, size_t *buflen,
|
||||
}
|
||||
|
||||
|
||||
/* Parse a key packet and store the ionformation in KI. */
|
||||
/* Parse a key packet and store the information in KI. */
|
||||
static gpg_error_t
|
||||
parse_key (const unsigned char *data, size_t datalen,
|
||||
struct _keybox_openpgp_key_info *ki)
|
||||
@ -243,6 +243,12 @@ parse_key (const unsigned char *data, size_t datalen,
|
||||
case 17: /* DSA */
|
||||
npkey = 4;
|
||||
break;
|
||||
case 18: /* ECDH */
|
||||
npkey = 3;
|
||||
break;
|
||||
case 19: /* ECDSA */
|
||||
npkey = 2;
|
||||
break;
|
||||
default: /* Unknown algorithm. */
|
||||
return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
|
||||
no-creation-time.gpg A key with a zero creation time.
|
||||
|
||||
ecc-sample-1-pub.asc The first ECC sample key.
|
||||
ecc-sample-1-sec.asc The first ECC sample key (secret).
|
||||
|
||||
|
22
tests/openpgp/samplekeys/ecc-sample-1-pub.asc
Normal file
22
tests/openpgp/samplekeys/ecc-sample-1-pub.asc
Normal file
@ -0,0 +1,22 @@
|
||||
The key has been generated by the first GnuPG ECC version at
|
||||
http://code.google.com/p/gnupg-ecc.
|
||||
|
||||
The sample key has ECDSA top key 0xBAA59D9C and a single ECDH
|
||||
encryption subkey 0x4089AB73. ECDH subkey uses SHA-256 and AES-128
|
||||
with KDF.
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v2.1.0-ecc (GNU/Linux)
|
||||
|
||||
mFIETJPQrRMIKoZIzj0DAQcCAwQLx6e669XwjHTHe3HuROe7C1oYMXuZbaU5PjOs
|
||||
xSkyxtL2D00e/jWgufuNN4ftS+6XygEtB7j1g1vnCTVF1TLmtCRlY19kc2FfZGhf
|
||||
MjU2IDxvcGVucGdwQGJyYWluaHViLm9yZz6IegQTEwgAIgUCTJPQrQIbAwYLCQgH
|
||||
AwIGFQgCCQoLBBYCAwECHgECF4AACgkQC6Ut8LqlnZzmXQEAiKgiSzPSpUOJcX9d
|
||||
JtLJ5As98Alit2oFwzhxG7mSVmQA/RP67yOeoUtdsK6bwmRA95cwf9lBIusNjehx
|
||||
XDfpHj+/uFYETJPQrRIIKoZIzj0DAQcCAwR/cMCoGEzcrqXbILqP7Rfke977dE1X
|
||||
XsRJEwrzftreZYrn7jXSDoiXkRyfVkvjPZqUvB5cknsaoH/3UNLRHClxAwEIB4hh
|
||||
BBgTCAAJBQJMk9CtAhsMAAoJEAulLfC6pZ2c1yYBAOSUmaQ8rkgihnepbnpK7tNz
|
||||
3QEocsLEtsTCDUBGNYGyAQDclifYqsUChXlWKaw3md+yHJPcWZXzHt37c4q/MhIm
|
||||
oQ==
|
||||
=hMzp
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
25
tests/openpgp/samplekeys/ecc-sample-1-sec.asc
Normal file
25
tests/openpgp/samplekeys/ecc-sample-1-sec.asc
Normal file
@ -0,0 +1,25 @@
|
||||
The key has been generated by the first GnuPG ECC version at
|
||||
http://code.google.com/p/gnupg-ecc.
|
||||
|
||||
The sample key has ECDSA top key 0xBAA59D9C and a single ECDH
|
||||
encryption subkey 0x4089AB73. ECDH subkey uses SHA-256 and AES-128
|
||||
with KDF. The password for the key is "ecc".
|
||||
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
Version: GnuPG v2.1.0-ecc (GNU/Linux)
|
||||
|
||||
lJ0ETJPQrRMIKoZIzj0DAQcCAwQLx6e669XwjHTHe3HuROe7C1oYMXuZbaU5PjOs
|
||||
xSkyxtL2D00e/jWgufuNN4ftS+6XygEtB7j1g1vnCTVF1TLm/gMDAmHomSLb9NbE
|
||||
oyWUoqgKTbZzbFR/SWmiCcuiQEhREcTyvyU1hAglj7FsBJoQ6/pbeAEQZ3bVzlNM
|
||||
8F0nF8KPLPuEADF1+4CntCRlY19kc2FfZGhfMjU2IDxvcGVucGdwQGJyYWluaHVi
|
||||
Lm9yZz6IegQTEwgAIgUCTJPQrQIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
|
||||
CgkQC6Ut8LqlnZzmXQEAiKgiSzPSpUOJcX9dJtLJ5As98Alit2oFwzhxG7mSVmQA
|
||||
/RP67yOeoUtdsK6bwmRA95cwf9lBIusNjehxXDfpHj+/nKEETJPQrRIIKoZIzj0D
|
||||
AQcCAwR/cMCoGEzcrqXbILqP7Rfke977dE1XXsRJEwrzftreZYrn7jXSDoiXkRyf
|
||||
VkvjPZqUvB5cknsaoH/3UNLRHClxAwEIB/4DAwJh6Jki2/TWxKO7gHKWIcOcxYZp
|
||||
CRWjlUghbKb6Q83p8GLPjKRN0USl/U1tObWdksqMXhUO0ePLWUnrbwoWYfYXg9Er
|
||||
ADTgCYhhBBgTCAAJBQJMk9CtAhsMAAoJEAulLfC6pZ2c1yYA/3eJRirPQZmBno+Z
|
||||
P/HOBSFWmFt4cUBGUx3oqiUd5loOAP480pb+vXx9ipljJWCJDSl/boRSuqB4hePP
|
||||
qt9Rd5gNdQ==
|
||||
=O8Dg
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
Loading…
x
Reference in New Issue
Block a user