From cvs at cvs.gnupg.org Tue Mar 4 11:20:37 2014 From: cvs at cvs.gnupg.org (by Dmitry Eremin-Solenikov) Date: Tue, 04 Mar 2014 11:20:37 +0100 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.6.0-58-g2b5403c Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 2b5403c408dfbd71be24c7635f5fa0b61ab4c9bb (commit) via ea8d597726305274214224757b32730644e12bd8 (commit) from 6be3032048ee2466511d2384fcf2d28b856219b2 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 2b5403c408dfbd71be24c7635f5fa0b61ab4c9bb Author: Dmitry Eremin-Solenikov Date: Sun Dec 22 17:13:45 2013 +0400 Add an utility to calculate hashes over a set of files * tests/gchash.c: New. -- An utility like rhash that has the ability to calculate different hashes over a set of files it usefull. Add gchash utility to calculate hashes supported by libgcrypt. Signed-off-by: Dmitry Eremin-Solenikov diff --git a/.gitignore b/.gitignore index ec7f8bb..8b235f9 100644 --- a/.gitignore +++ b/.gitignore @@ -69,6 +69,7 @@ tests/basic tests/benchmark tests/fips186-dsa tests/fipsdrv +tests/gchash tests/hmac tests/keygen tests/keygrip diff --git a/tests/Makefile.am b/tests/Makefile.am index 4cf7a44..9f8839a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -51,7 +51,8 @@ standard_ldadd = \ ../compat/libcompat.la EXTRA_PROGRAMS = testapi pkbench -noinst_PROGRAMS = $(tests_bin) $(tests_bin_last) fipsdrv rsacvt genhashdata +noinst_PROGRAMS = $(tests_bin) $(tests_bin_last) fipsdrv rsacvt genhashdata \ + gchash noinst_HEADERS = t-common.h EXTRA_DIST = README rsa-16k.key cavs_tests.sh cavs_driver.pl \ diff --git a/tests/gchash.c b/tests/gchash.c new file mode 100644 index 0000000..7a2aad6 --- /dev/null +++ b/tests/gchash.c @@ -0,0 +1,120 @@ +/* gchash.c - Calculate hash values + * Copyright (C) 2013 Dmitry Eremin-Solenikov + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include + +#ifdef _GCRYPT_IN_LIBGCRYPT +# undef _GCRYPT_IN_LIBGCRYPT +# include "gcrypt.h" +#else +# include +#endif + + +void +init_gcrypt (void) +{ + if (!gcry_check_version (GCRYPT_VERSION)) { + fputs ("libgcrypt version mismatch\n", stderr); + exit (2); + } + + gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN); + + /* Allocate a pool of 16k secure memory. This make the secure memory + * available and also drops privileges where needed. */ + gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0); + + gcry_control (GCRYCTL_RESUME_SECMEM_WARN); + + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); +} + +int +main (int argc, char **argv) +{ + gcry_md_hd_t hd; + gcry_error_t err; + int algo; + + init_gcrypt(); + + if (argc < 2 || (argv[1] && !strcmp(argv[1], "--help"))) + { + fprintf (stderr, "Usage: %s ...\n", argv[0]); + return 1; + } + + algo = gcry_md_map_name (argv[1]); + if (algo == GCRY_MD_NONE) + { + fprintf (stderr, "Unknown algorithm '%s'\n", argv[1]); + return 1; + } + + err = gcry_md_open(&hd, algo, 0); + if (err) + { + fprintf (stderr, "LibGCrypt error %s/%s\n", + gcry_strsource (err), + gcry_strerror (err)); + exit (1); + } + + for (argv += 2; *argv; argv++) + { + FILE *fp; + unsigned char buf[1024]; + size_t size; + int i; + unsigned char *h; + if (!strcmp (*argv, "-")) + fp = stdin; + else + fp = fopen (*argv, "r"); + + if (fp == NULL) + { + perror ("fopen"); + return 1; + } + + while (!feof (fp)) + { + size = fread (buf, 1, sizeof(buf), fp); + gcry_md_write (hd, buf, size); + } + + h = gcry_md_read(hd, 0); + + for (i = 0; i < gcry_md_get_algo_dlen (algo); i++) + printf("%02hhx", h[i]); + printf(" %s\n", *argv); + + gcry_md_reset(hd); + } + + gcry_md_close(hd); + return 0; +} commit ea8d597726305274214224757b32730644e12bd8 Author: Dmitry Eremin-Solenikov Date: Sun Dec 22 17:12:28 2013 +0400 Add a simple (raw) PKCS#1 padding mode * src/cipher.h (PUBKEY_ENC_PKCS1_RAW): New. * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist): Handle pkcs1-raw flag. * cipher/pubkey-util.c (_gcry_pk_util_data_to_mpi): Handle s-exp like (data (flags pkcs1-raw) (value xxxxx)) * cipher/rsa-common.c (_gcry_rsa_pkcs1_encode_raw_for_sig): PKCS#1-encode data with embedded hash OID for signature verification. * tests/basic.c (check_pubkey_sign): Add tests for s-exps with pkcs1-raw flag. -- Allow user to specify (flags pkcs1-raw) to enable pkcs1 padding of raw value (no hash algorithm is specified). It is up to the user to verify that the passed value is properly formatted and includes DER-encoded ASN OID of the used hash function. Signed-off-by: Dmitry Eremin-Solenikov diff --git a/cipher/pubkey-internal.h b/cipher/pubkey-internal.h index 193248c..b8167c7 100644 --- a/cipher/pubkey-internal.h +++ b/cipher/pubkey-internal.h @@ -56,6 +56,10 @@ gpg_err_code_t _gcry_rsa_pkcs1_decode_for_enc (unsigned char **r_result, size_t *r_resultlen, unsigned int nbits, gcry_mpi_t value); gpg_err_code_t +_gcry_rsa_pkcs1_encode_raw_for_sig (gcry_mpi_t *r_result, unsigned int nbits, + const unsigned char *value, size_t valuelen); + +gpg_err_code_t _gcry_rsa_pkcs1_encode_for_sig (gcry_mpi_t *r_result, unsigned int nbits, const unsigned char *value, size_t valuelen, int algo); diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c index 616b499..514f1eb 100644 --- a/cipher/pubkey-util.c +++ b/cipher/pubkey-util.c @@ -142,6 +142,16 @@ _gcry_pk_util_parse_flaglist (gcry_sexp_t list, rc = GPG_ERR_INV_FLAG; break; + case 9: + if (!memcmp (s, "pkcs1-raw", 9) && encoding == PUBKEY_ENC_UNKNOWN) + { + encoding = PUBKEY_ENC_PKCS1_RAW; + flags |= PUBKEY_FLAG_FIXEDLEN; + } + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + case 10: if (!memcmp (s, "igninvflag", 10)) igninvflag = 1; @@ -850,6 +860,21 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, ctx->hash_algo); } } + else if (ctx->encoding == PUBKEY_ENC_PKCS1_RAW && lvalue + && (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY)) + { + const void * value; + size_t valuelen; + + if (sexp_length (lvalue) != 2) + rc = GPG_ERR_INV_OBJ; + else if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) + || !valuelen ) + rc = GPG_ERR_INV_OBJ; + else + rc = _gcry_rsa_pkcs1_encode_raw_for_sig (ret_mpi, ctx->nbits, + value, valuelen); + } else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue && ctx->op == PUBKEY_OP_ENCRYPT) { diff --git a/cipher/rsa-common.c b/cipher/rsa-common.c index 4f5a659..f56e989 100644 --- a/cipher/rsa-common.c +++ b/cipher/rsa-common.c @@ -319,6 +319,71 @@ _gcry_rsa_pkcs1_encode_for_sig (gcry_mpi_t *r_result, unsigned int nbits, return rc; } +/* Encode {VALUE,VALUELEN} for an NBITS keys using the pkcs#1 block + type 1 padding. On success the result is stored as a new MPI at + R_RESULT. On error the value at R_RESULT is undefined. + + We encode the value in this way: + + 0 1 PAD(n bytes) 0 VALUE(valuelen bytes) + + 0 is a marker we unfortunately can't encode because we return an + MPI which strips all leading zeroes. + 1 is the block type. + PAD consists of 0xff bytes. + 0 marks the end of the padding. + + (Note that PGP prior to version 2.3 encoded the message digest as: + 0 1 MD(16 bytes) 0 PAD(n bytes) 1 + The MD is always 16 bytes here because it's always MD5. GnuPG + does not not support pre-v2.3 signatures, but I'm including this + comment so the information is easily found if needed.) +*/ +gpg_err_code_t +_gcry_rsa_pkcs1_encode_raw_for_sig (gcry_mpi_t *r_result, unsigned int nbits, + const unsigned char *value, size_t valuelen) +{ + gcry_err_code_t rc = 0; + gcry_error_t err; + byte *frame = NULL; + size_t nframe = (nbits+7) / 8; + int i; + size_t n; + + if ( !valuelen || valuelen + 4 > nframe) + { + /* Can't encode an DLEN byte digest MD into an NFRAME byte + frame. */ + return GPG_ERR_TOO_SHORT; + } + + if ( !(frame = xtrymalloc (nframe)) ) + return gpg_err_code_from_syserror (); + + /* Assemble the pkcs#1 block type 1. */ + n = 0; + frame[n++] = 0; + frame[n++] = 1; /* block type */ + i = nframe - valuelen - 3 ; + gcry_assert (i > 1); + memset (frame+n, 0xff, i ); + n += i; + frame[n++] = 0; + memcpy (frame+n, value, valuelen ); + n += valuelen; + gcry_assert (n == nframe); + + /* Convert it into an MPI. */ + err = _gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, n, &nframe); + if (err) + rc = gcry_err_code (err); + else if (DBG_CIPHER) + log_mpidump ("PKCS#1 block type 1 encoded data", *r_result); + xfree (frame); + + return rc; +} + /* Mask generation function for OAEP. See RFC-3447 B.2.1. */ static gcry_err_code_t diff --git a/src/cipher.h b/src/cipher.h index 10bfe0c..26ffddc 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -54,6 +54,7 @@ enum pk_encoding { PUBKEY_ENC_RAW, PUBKEY_ENC_PKCS1, + PUBKEY_ENC_PKCS1_RAW, PUBKEY_ENC_OAEP, PUBKEY_ENC_PSS, PUBKEY_ENC_UNKNOWN diff --git a/tests/basic.c b/tests/basic.c index 4474a9d..e21e055 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -5155,6 +5155,10 @@ check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo) " (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n", GCRY_PK_RSA, 0 }, + { "(data\n (flags pkcs1-raw)\n" + " (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n", + GCRY_PK_RSA, + GPG_ERR_CONFLICT }, { "(data\n (flags oaep)\n" " (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n", 0, @@ -5187,6 +5191,10 @@ check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo) " (value #11223344556677889900AA#))\n", GCRY_PK_RSA, GPG_ERR_CONFLICT }, + { "(data\n (flags pkcs1-raw)\n" + " (value #11223344556677889900AA#))\n", + GCRY_PK_RSA, + 0 }, { "(data\n (flags raw foo)\n" " (value #11223344556677889900AA#))\n", 0, ----------------------------------------------------------------------- Summary of changes: .gitignore | 1 + cipher/pubkey-internal.h | 4 ++ cipher/pubkey-util.c | 25 ++++++++++ cipher/rsa-common.c | 65 +++++++++++++++++++++++++ src/cipher.h | 1 + tests/Makefile.am | 3 +- tests/basic.c | 8 ++++ tests/gchash.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 tests/gchash.c hooks/post-receive -- The GNU crypto library http://git.gnupg.org From cvs at cvs.gnupg.org Wed Mar 5 08:15:51 2014 From: cvs at cvs.gnupg.org (by Daiki Ueno) Date: Wed, 05 Mar 2014 08:15:51 +0100 Subject: [git] GPGME - branch, master, updated. gpgme-1.4.2-23-g40938fe Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 40938feb3f3393b0cdc6ec61ca2e77ff0b82c69a (commit) from 651d9e1c6bc1cab248024c3850ef64698247588f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 40938feb3f3393b0cdc6ec61ca2e77ff0b82c69a Author: Daiki Ueno Date: Wed Mar 5 14:52:49 2014 +0900 doc: Fix documentation of struct data types * gpgme.texi (Key Management): Document is_cardkey and card_number members of gpgme_subkey_t. (Decrypt): Remove description of the non-existent wrong_key_usage member of gpgme_recipient_t. (Verify): Document pka_address member of gpgme_signature_t. (Creating a Signature): Add missing member names in gpgme_new_signature_t. (Registering I/O Callbacks): Fix reference of gpgme_io_cbs struct. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 3f31492..4425396 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -2689,6 +2689,12 @@ timestamp is invalid, and 0 if it is not available. @item long int expires This is the expiration timestamp of the subkey, or 0 if the subkey does not expire. + + at item unsigned int is_cardkey : 1 +True if the secret key is stored on a smart card. + + at item char *card_number +The serial number of a smart card holding this key or @code{NULL}. @end table @end deftp @@ -4213,9 +4219,6 @@ or @code{NULL} if this is the last element. @item gpgme_pubkey_algo_t The public key algorithm used in the encryption. - at item unsigned int wrong_key_usage : 1 -This is true if the key was not used according to its policy. - @item char *keyid This is the key ID of the key (in hexadecimal digits) used as recipient. @@ -4509,6 +4512,9 @@ The public key algorithm used to create this signature. @item gpgme_hash_algo_t The hash algorithm used to create this signature. + + at item char *pka_address +The mailbox from the PKA information or @code{NULL}. @end table @end deftp @@ -4945,10 +4951,10 @@ list, or @code{NULL} if this is the last element. @item gpgme_sig_mode_t type The type of this signature. - at item gpgme_pubkey_algo_t + at item gpgme_pubkey_algo_t pubkey_algo The public key algorithm used to create this signature. - at item gpgme_hash_algo_t + at item gpgme_hash_algo_t hash_algo The hash algorithm used to create this signature. @item unsigned int sig_class @@ -5400,7 +5406,7 @@ list of possible @code{gpgme_event_io_t} types. @node Registering I/O Callbacks @subsubsection Registering I/O Callbacks - at deftp {Data type} {struct gpgme_io_cb_ts} + at deftp {Data type} {struct gpgme_io_cbs} @tindex gpgme_event_io_t This structure is used to store the I/O callback interface functions described in the previous section. It has the following members: @@ -5410,7 +5416,7 @@ described in the previous section. It has the following members: This is the function called by @acronym{GPGME} to register an I/O callback handler. It must be specified. - at item void *add_data + at item void *add_priv This is passed as the first argument to the @code{add} function when it is called by @acronym{GPGME}. For example, it can be used to determine the event loop to which the file descriptor should be added. @@ -5424,14 +5430,14 @@ This is the function called by @acronym{GPGME} to signal an event for an operation. It must be specified, because at least the start event must be processed. - at item void *event_data + at item void *event_priv This is passed as the first argument to the @code{event} function when it is called by @acronym{GPGME}. For example, it can be used to determine the context in which the event has occured. @end table @end deftp - at deftypefun void gpgme_set_io_cbs (@w{gpgme_ctx_t @var{ctx}}, @w{struct gpgme_io_cb_ts *@var{io_cbs}}) + at deftypefun void gpgme_set_io_cbs (@w{gpgme_ctx_t @var{ctx}}, @w{struct gpgme_io_cbs *@var{io_cbs}}) The function @code{gpgme_set_io_cbs} enables the I/O callback interface for the context @var{ctx}. The I/O callback functions are specified by @var{io_cbs}. @@ -5440,7 +5446,7 @@ If @var{io_cbs}->@code{add} is @code{NULL}, the I/O callback interface is disabled for the context, and normal operation is restored. @end deftypefun - at deftypefun void gpgme_get_io_cbs (@w{gpgme_ctx_t @var{ctx}}, @w{struct gpgme_io_cb_ts *@var{io_cbs}}) + at deftypefun void gpgme_get_io_cbs (@w{gpgme_ctx_t @var{ctx}}, @w{struct gpgme_io_cbs *@var{io_cbs}}) The function @code{gpgme_get_io_cbs} returns the I/O callback functions set with @code{gpgme_set_io_cbs} in @var{io_cbs}. @end deftypefun @@ -5630,7 +5636,7 @@ main (int argc, char *argv[]) gpgme_error_t err; gpgme_data_t sig, text; int i; - struct gpgme_io_cb_ts io_cbs = + struct gpgme_io_cbs io_cbs = @{ add_io_cb, &loop, ----------------------------------------------------------------------- Summary of changes: doc/gpgme.texi | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Wed Mar 5 14:00:23 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Wed, 05 Mar 2014 14:00:23 +0100 Subject: [git] GpgEX - branch, master, updated. gpgex-1.0.0-4-gda8aeee Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnupG extension for the Windows Explorer". The branch, master has been updated via da8aeee958e8943aad57a4b178e2f39a3897e4c6 (commit) from 4b230c7604ba61fec0d6ee78390065207dd6c606 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit da8aeee958e8943aad57a4b178e2f39a3897e4c6 Author: Werner Koch Date: Wed Mar 5 13:37:35 2014 +0100 Lock the spawning of a new UI server. * src/exechelp.c (gpgex_lock_spawning): New. (gpgex_unlock_spawning): New. * src/client.cc (uiserver_connect): Use the new lock functions. -- The locking is required to be sure that only one UI server is started. The lock code has been taken from GnuPG (common/asshelp.c) of which g10 Code is the sole author. diff --git a/NEWS b/NEWS index 23c5e30..5415c9a 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ Noteworthy changes for version 1.0.1 (unreleased) ------------------------------------------------- +* Avoid double starting of the UI-server. + + Noteworthy changes for version 1.0.0 (2013-07-30) ------------------------------------------------- diff --git a/src/client.cc b/src/client.cc index 37fe7ef..8350181 100644 --- a/src/client.cc +++ b/src/client.cc @@ -1,5 +1,5 @@ /* client.cc - gpgex assuan client implementation - Copyright (C) 2007, 2008, 2013 g10 Code GmbH + Copyright (C) 2007, 2008, 2013, 2014 g10 Code GmbH This file is part of GpgEX. @@ -295,6 +295,7 @@ uiserver_connect (assuan_context_t *ctx, HWND hwnd) gpg_error_t rc; const char *socket_name = NULL; pid_t pid; + lock_spawn_t lock; TRACE_BEG (DEBUG_ASSUAN, "client_t::uiserver_connect", ctx); @@ -320,19 +321,26 @@ uiserver_connect (assuan_context_t *ctx, HWND hwnd) (void) TRACE_LOG ("UI server not running, starting it"); - rc = gpgex_spawn_detached (default_uiserver_cmdline ()); - if (rc) - return TRACE_GPGERR (rc); + /* Now try to connect again with the spawn lock taken. */ + if (!(rc = gpgex_lock_spawning (&lock)) + && assuan_socket_connect (*ctx, socket_name, -1, 0)) + { + rc = gpgex_spawn_detached (default_uiserver_cmdline ()); + if (!rc) + { + /* Give it a bit of time to start up and try a couple of + times. */ + for (count = 0; count < 10; count++) + { + Sleep (1000); + rc = assuan_socket_connect (*ctx, socket_name, -1, 0); + if (!rc) + break; + } + } - /* Give it a bit of time to start up and try a couple of - times. */ - for (count = 0; count < 10; count++) - { - Sleep (1000); - rc = assuan_socket_connect (*ctx, socket_name, -1, 0); - if (!rc) - break; - } + } + gpgex_unlock_spawning (&lock); } if (! rc) diff --git a/src/exechelp.c b/src/exechelp.c index 47e3e27..7ce28ba 100644 --- a/src/exechelp.c +++ b/src/exechelp.c @@ -1,5 +1,5 @@ /* exechelp.c - fork and exec helpers - * Copyright (C) 2004, 2007 g10 Code GmbH + * Copyright (C) 2004, 2007, 2014 g10 Code GmbH * * This file is part of GpgEX. * @@ -37,7 +37,62 @@ /* Define to 1 do enable debugging. */ #define DEBUG_W32_SPAWN 0 + + +/* Lock a spawning process. The caller needs to provide the address + of a variable to store the lock information and the name or the + process. */ +gpg_error_t +gpgex_lock_spawning (lock_spawn_t *lock) +{ + int waitrc; + int timeout = 5; + + _TRACE (DEBUG_ASSUAN, "gpgex_lock_spawning", lock); + + *lock = CreateMutexW (NULL, FALSE, L"spawn_gnupg_uiserver_sentinel"); + if (!*lock) + { + TRACE_LOG1 ("failed to create the spawn mutex: rc=%d", GetLastError ()); + return gpg_error (GPG_ERR_GENERAL); + } + + retry: + waitrc = WaitForSingleObject (*lock, 1000); + if (waitrc == WAIT_OBJECT_0) + return 0; + + if (waitrc == WAIT_TIMEOUT && timeout) + { + timeout--; + goto retry; + } + if (waitrc == WAIT_TIMEOUT) + TRACE_LOG ("error waiting for the spawn mutex: timeout"); + else + TRACE_LOG2 ("error waiting for the spawn mutex: (code=%d) rc=%d", + waitrc, GetLastError ()); + return gpg_error (GPG_ERR_GENERAL); +} + + +/* Unlock the spawning process. */ +void +gpgex_unlock_spawning (lock_spawn_t *lock) +{ + if (*lock) + { + _TRACE (DEBUG_ASSUAN, "gpgex_unlock_spawning", lock); + + if (!ReleaseMutex (*lock)) + TRACE_LOG1 ("failed to release the spawn mutex: rc=%d", GetLastError()); + CloseHandle (*lock); + *lock = NULL; + } +} + + /* Fork and exec the program with /dev/null as stdin, stdout and stderr. Returns 0 on success or an error code. */ gpg_error_t diff --git a/src/exechelp.h b/src/exechelp.h index a08855d..389da37 100644 --- a/src/exechelp.h +++ b/src/exechelp.h @@ -30,9 +30,15 @@ extern "C" { #endif #endif +#define lock_spawn_t HANDLE + +gpg_error_t gpgex_lock_spawning (lock_spawn_t *lock); +void gpgex_unlock_spawning (lock_spawn_t *lock); + /* Fork and exec CMDLINE with /dev/null as stdin, stdout and stderr. Returns 0 on success or an error code. */ gpg_error_t gpgex_spawn_detached (const char *cmdline); + #ifdef __cplusplus #if 0 { ----------------------------------------------------------------------- Summary of changes: NEWS | 3 +++ src/client.cc | 34 ++++++++++++++++++++------------- src/exechelp.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/exechelp.h | 6 ++++++ 4 files changed, 86 insertions(+), 14 deletions(-) hooks/post-receive -- GnupG extension for the Windows Explorer http://git.gnupg.org From cvs at cvs.gnupg.org Thu Mar 6 08:28:40 2014 From: cvs at cvs.gnupg.org (by NIIBE Yutaka) Date: Thu, 06 Mar 2014 08:28:40 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-314-g5ed8e93 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 5ed8e9335fb886d7ddc86728d8481e5e47485531 (commit) from 0f38c87f427a155ab5684e18e3b73956f81edfab (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 5ed8e9335fb886d7ddc86728d8481e5e47485531 Author: NIIBE Yutaka Date: Thu Mar 6 16:23:10 2014 +0900 Fix g10/trust.c. * g10/trust.c (register_trusted_keyid, register_trusted_key) (update_ownertrust): Call functions with tdb_. Signed-off-by: NIIBE Yutaka diff --git a/g10/trust.c b/g10/trust.c index 32cd934..c8a1c2c 100644 --- a/g10/trust.c +++ b/g10/trust.c @@ -55,7 +55,7 @@ register_trusted_keyid (u32 *keyid) #ifdef NO_TRUST_MODELS (void)keyid; #else - register_trusted_keyid (keyid); + tdb_register_trusted_keyid (keyid); #endif } @@ -66,7 +66,7 @@ register_trusted_key (const char *string) #ifdef NO_TRUST_MODELS (void)string; #else - register_trusted_key (string); + tdb_register_trusted_key (string); #endif } @@ -247,7 +247,7 @@ update_ownertrust (PKT_public_key *pk, unsigned int new_trust) (void)pk; (void)new_trust; #else - update_ownertrust (pk, new_trust); + tdb_update_ownertrust (pk, new_trust); #endif } ----------------------------------------------------------------------- Summary of changes: g10/trust.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Thu Mar 6 15:29:42 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 06 Mar 2014 15:29:42 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-315-g191e320 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 191e32026f02054b1edb4f02536875462fd0b6b3 (commit) from 5ed8e9335fb886d7ddc86728d8481e5e47485531 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 191e32026f02054b1edb4f02536875462fd0b6b3 Author: Werner Koch Date: Thu Mar 6 15:28:42 2014 +0100 common: Fix recent commit 55656208. * common/membuf.c (get_membuf_shrink): Fix use of LEN. -- Oops, what a stupid bug. diff --git a/common/membuf.c b/common/membuf.c index 884c08c..6c9fee9 100644 --- a/common/membuf.c +++ b/common/membuf.c @@ -181,12 +181,12 @@ get_membuf_shrink (membuf_t *mb, size_t *len) if (!len) len = &dummylen; - p = get_membuf (mb, &len); + p = get_membuf (mb, len); if (!p) return NULL; - if (len) + if (*len) { - pp = xtryrealloc (p, len); + pp = xtryrealloc (p, *len); if (pp) p = pp; } ----------------------------------------------------------------------- Summary of changes: common/membuf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Thu Mar 6 15:50:08 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 06 Mar 2014 15:50:08 +0100 Subject: [git] GPA - branch, master, updated. gpa-0.9.4-19-ga74c296 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Assistant". The branch, master has been updated via a74c29602482d361d289dc6248208fa6f2bc36c4 (commit) from cb0e2c95aafaab607ae7f040a79e3b47db80ee0f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a74c29602482d361d289dc6248208fa6f2bc36c4 Author: Werner Koch Date: Thu Mar 6 15:44:44 2014 +0100 Fix double window bug with ENCRYPT_SIGN_FILES. * src/server.c (impl_encrypt_sign_files): s/if/else if/. diff --git a/src/server.c b/src/server.c index 17ebde3..6bbbef3 100644 --- a/src/server.c +++ b/src/server.c @@ -1284,7 +1284,7 @@ impl_encrypt_sign_files (assuan_context_t ctx, int encr, int sign) if (encr && sign) op = (GpaFileOperation *) gpa_file_encrypt_sign_operation_new (NULL, ctrl->files, FALSE); - if (encr) + else if (encr) op = (GpaFileOperation *) gpa_file_encrypt_operation_new (NULL, ctrl->files, FALSE); else ----------------------------------------------------------------------- Summary of changes: src/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- The GNU Privacy Assistant http://git.gnupg.org From cvs at cvs.gnupg.org Thu Mar 6 16:21:20 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 06 Mar 2014 16:21:20 +0100 Subject: [git] GnuPG - branch, STABLE-BRANCH-1-4, updated. gnupg-1.4.15-15-g23191d7 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, STABLE-BRANCH-1-4 has been updated via 23191d7851eae2217ecdac6484349849a24fd94a (commit) from 24ba0ce93263c42afb9f087ffcf2edda0b433022 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 23191d7851eae2217ecdac6484349849a24fd94a Author: Werner Koch Date: Thu Mar 6 16:11:34 2014 +0100 gpg: Need to init the trustdb for import. * g10/trustdb.c (clear_ownertrusts): Init trustdb. -- This is actually a hack to fix a bug introduced with commit 2528178. Debian uses it and thus we should do too. GnuPG-bug-id: 1622 diff --git a/g10/trustdb.c b/g10/trustdb.c index 0bf92e4..a541106 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -927,6 +927,7 @@ clear_ownertrusts (PKT_public_key *pk) TRUSTREC rec; int rc; + init_trustdb (); if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) return 0; ----------------------------------------------------------------------- Summary of changes: g10/trustdb.c | 1 + 1 file changed, 1 insertion(+) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Fri Mar 7 10:56:53 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Fri, 07 Mar 2014 10:56:53 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-331-g0fc71f7 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 0fc71f7277c6f833f838bbd384f1a22d0c333e8e (commit) via d8f0b83e4f04641e5e9adbdd8abada15380f981c (commit) via dfb25d47a9fcfd7c7c084ea58744724cd5315086 (commit) via db1f74ba5338f624f146a3cb41a346e46b15c8f9 (commit) via 90688b29f3701f4d3e2a5a49c5544fe8d2a84b2d (commit) via 7c4bfa599fa69c3a942c8deea83737a4c5a0806e (commit) via 5ca482d5f949444ffd453de158ee186ab07fc9b6 (commit) via 0ab752cc2d46bbd0077bed889676169b7aeb1eb6 (commit) via 76b1940ad6f5f058c4a6bec35902da9f6d4e27b0 (commit) via 63b7658a29809249d7aeb0423bf8c5a693eee0c7 (commit) via 9942a149ff2ab919c1b2916c7bc347e578a56b14 (commit) via 5105c8d2d344fd7301d456d8c13c7e90a54f7e98 (commit) via 179012ddd48e63ca83e8f5c24537a2db45c3e122 (commit) via 4ad123d6fe341da7768e43360375e17fa89e8e0d (commit) via d2a6be24af0bf220bb448fdd50c0196faddee0f4 (commit) via 8fc9de8d6bf663f7c8419b42dab01f590a694d59 (commit) from 191e32026f02054b1edb4f02536875462fd0b6b3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 0fc71f7277c6f833f838bbd384f1a22d0c333e8e Author: Werner Koch Date: Fri Nov 15 09:08:58 2013 +0100 common: Fix build problem with Sun Studio compiler. * common/estream.c (ESTREAM_MUTEX_UNLOCK): Use int dummy dummy functions. (ESTREAM_MUTEX_INITIALIZE): Ditto. -- GnuPG-bug-id: 1566 Signed-off-by: Werner Koch (cherry picked from commit 571bcd4662a351cfa55bbf1a79ed1bc26da5780f) Reolved conflicts: common/estream.c Warning: estream.c still uses pth_mutex_* which is definitely wrong. Needs to be investigated. diff --git a/common/estream.c b/common/estream.c index 79e3efb..9c15100 100644 --- a/common/estream.c +++ b/common/estream.c @@ -171,7 +171,8 @@ typedef pth_mutex_t estream_mutex_t; ((pth_mutex_acquire (&(mutex), 1, NULL) == TRUE) ? 0 : -1) # define ESTREAM_MUTEX_INITIALIZE(mutex) \ pth_mutex_init (&(mutex)) -#else + +#else /*!HAVE_NPTH*/ typedef void *estream_mutex_t; @@ -190,10 +191,11 @@ dummy_mutex_call_int (estream_mutex_t mutex) # define ESTREAM_MUTEX_INITIALIZER NULL # define ESTREAM_MUTEX_LOCK(mutex) dummy_mutex_call_void ((mutex)) -# define ESTREAM_MUTEX_UNLOCK(mutex) dummy_mutex_call_void ((mutex)) +# define ESTREAM_MUTEX_UNLOCK(mutex) dummy_mutex_call_int ((mutex)) # define ESTREAM_MUTEX_TRYLOCK(mutex) dummy_mutex_call_int ((mutex)) -# define ESTREAM_MUTEX_INITIALIZE(mutex) dummy_mutex_call_void ((mutex)) -#endif +# define ESTREAM_MUTEX_INITIALIZE(mutex) dummy_mutex_call_int ((mutex)) + +#endif /*!HAVE_NPTH*/ /* Primitive system I/O. */ commit d8f0b83e4f04641e5e9adbdd8abada15380f981c Author: Werner Koch Date: Fri Oct 11 09:25:58 2013 +0200 gpg: Do not require a trustdb with --always-trust. * g10/tdbio.c (tdbio_set_dbname): Add arg R_NOFILE. * g10/trustdb.c (trustdb_args): Add field no_trustdb. (init_trustdb): Set that field. (revalidation_mark): Take care of a nonexistent trustdb file. (read_trust_options): Ditto. (tdb_get_ownertrust): Ditto. (tdb_get_min_ownertrust): Ditto. (tdb_update_ownertrust): Ditto. (update_min_ownertrust): Ditto. (tdb_clear_ownertrusts): Ditto. (tdb_cache_disabled_value): Ditto. (tdb_check_trustdb_stale): Ditto. (tdb_get_validity_core): Ditto. * g10/gpg.c (main): Do not create a trustdb with most commands for trust-model always. -- This slightly changes the semantics of most commands in that they won't create a trustdb if --trust-model=always is used. It just does not make sense to create a trustdb if there is no need for it. Signed-off-by: Werner Koch (cherry picked from commit 1a0eeaacd1bf09fe5125dbc3f56016bc20f3512e) Resolved conflicts: NEWS g10/trustdb.c: Manually apply changes due to changed function names. Note that this also includes the fix for clear_ownertrust, see GnuPG-bug-id: 1622. diff --git a/NEWS b/NEWS index 2efc395..da771f1 100644 --- a/NEWS +++ b/NEWS @@ -38,6 +38,10 @@ Noteworthy changes in version 2.1.0-betaN (unreleased) * Only the major version number is by default included in the armored output. + * Do not create a trustdb file if --trust-model=always is used. + + * Protect against rogue keyservers sending secret keys. + Noteworthy changes in version 2.1.0beta3 (2011-12-20) ----------------------------------------------------- diff --git a/g10/gpg.c b/g10/gpg.c index 15cbe4b..65a9cab 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -3539,15 +3539,11 @@ main (int argc, char **argv) case aListTrustDB: rc = setup_trustdb (argc? 1:0, trustdb_name); break; - case aEncr: - case aEncrFiles: + default: /* If we are using TM_ALWAYS, we do not need to create the trustdb. */ rc = setup_trustdb (opt.trust_model != TM_ALWAYS, trustdb_name); break; - default: - rc = setup_trustdb (1, trustdb_name ); - break; } if (rc) log_error (_("failed to initialize the TrustDB: %s\n"), g10_errstr(rc)); diff --git a/g10/tdbio.c b/g10/tdbio.c index 0a659b1..db7a67c 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -480,7 +480,7 @@ create_version_record (void) int -tdbio_set_dbname( const char *new_dbname, int create ) +tdbio_set_dbname( const char *new_dbname, int create, int *r_nofile) { char *fname; static int initialized = 0; @@ -490,6 +490,8 @@ tdbio_set_dbname( const char *new_dbname, int create ) initialized = 1; } + *r_nofile = 0; + if(new_dbname==NULL) fname=make_filename(opt.homedir,"trustdb" EXTSEP_S GPGEXT_GPG, NULL); else if (*new_dbname != DIRSEP_C ) @@ -515,7 +517,9 @@ tdbio_set_dbname( const char *new_dbname, int create ) xfree(fname); return G10ERR_TRUSTDB; } - if( create ) { + if (!create) + *r_nofile = 1; + else { FILE *fp; TRUSTREC rec; int rc; diff --git a/g10/tdbio.h b/g10/tdbio.h index 252a393..4f37de4 100644 --- a/g10/tdbio.h +++ b/g10/tdbio.h @@ -93,7 +93,7 @@ typedef struct trust_record TRUSTREC; /*-- tdbio.c --*/ int tdbio_update_version_record(void); -int tdbio_set_dbname( const char *new_dbname, int create ); +int tdbio_set_dbname( const char *new_dbname, int create, int *r_nofile); const char *tdbio_get_dbname(void); void tdbio_dump_record( TRUSTREC *rec, FILE *fp ); int tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected ); diff --git a/g10/trustdb.c b/g10/trustdb.c index 733fa79..ea07399 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -49,19 +49,22 @@ typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */ * the item right after the last one has a keyblock set to NULL. * Maybe we can drop this thing and replace it by key_item */ -struct key_array { +struct key_array +{ KBNODE keyblock; }; -/* control information for the trust DB */ -static struct { - int init; - int level; - char *dbname; +/* Control information for the trust DB. */ +static struct +{ + int init; + int level; + char *dbname; + int no_trustdb; } trustdb_args; -/* some globals */ +/* Some globals. */ static struct key_item *user_utk_list; /* temp. used to store --trusted-keys */ static struct key_item *utk_list; /* all ultimately trusted keys */ @@ -417,7 +420,7 @@ how_to_fix_the_trustdb () void -init_trustdb() +init_trustdb () { int level = trustdb_args.level; const char* dbname = trustdb_args.dbname; @@ -429,7 +432,7 @@ init_trustdb() if(level==0 || level==1) { - int rc = tdbio_set_dbname( dbname, !!level ); + int rc = tdbio_set_dbname( dbname, !!level, &trustdb_args.no_trustdb); if( rc ) log_fatal("can't init trustdb: %s\n", g10_errstr(rc) ); } @@ -525,10 +528,13 @@ void tdb_revalidation_mark (void) { init_trustdb(); - /* we simply set the time for the next check to 1 (far back in 1970) - * so that a --update-trustdb will be scheduled */ + if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) + return; + + /* We simply set the time for the next check to 1 (far back in 1970) + so that a --update-trustdb will be scheduled. */ if (tdbio_write_nextcheck (1)) - do_sync (); + do_sync (); pending_check_trustdb = 1; } @@ -560,8 +566,10 @@ read_trust_options(byte *trust_model,ulong *created,ulong *nextcheck, TRUSTREC opts; init_trustdb(); - - read_record(0,&opts,RECTYPE_VER); + if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) + memset (&opts, 0, sizeof opts); + else + read_record (0, &opts, RECTYPE_VER); if(trust_model) *trust_model=opts.r.ver.trust_model; @@ -619,6 +627,9 @@ tdb_get_ownertrust ( PKT_public_key *pk) TRUSTREC rec; int rc; + if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) + return TRUST_UNKNOWN; + rc = read_trust_record (pk, &rec); if (rc == -1) return TRUST_UNKNOWN; /* no record yet */ @@ -638,6 +649,9 @@ tdb_get_min_ownertrust (PKT_public_key *pk) TRUSTREC rec; int rc; + if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) + return TRUST_UNKNOWN; + rc = read_trust_record (pk, &rec); if (rc == -1) return TRUST_UNKNOWN; /* no record yet */ @@ -661,6 +675,9 @@ tdb_update_ownertrust (PKT_public_key *pk, unsigned int new_trust ) TRUSTREC rec; int rc; + if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) + return; + rc = read_trust_record (pk, &rec); if (!rc) { @@ -705,6 +722,9 @@ update_min_ownertrust (u32 *kid, unsigned int new_trust ) TRUSTREC rec; int rc; + if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) + return; + pk = xmalloc_clear (sizeof *pk); rc = get_pubkey (pk, kid); if (rc) @@ -761,6 +781,11 @@ tdb_clear_ownertrusts (PKT_public_key *pk) TRUSTREC rec; int rc; + init_trustdb (); + + if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) + return 0; + rc = read_trust_record (pk, &rec); if (!rc) { @@ -865,6 +890,9 @@ tdb_cache_disabled_value (PKT_public_key *pk) init_trustdb(); + if (trustdb_args.no_trustdb) + return 0; /* No trustdb => not disabled. */ + rc = read_trust_record (pk, &trec); if (rc && rc != -1) { @@ -893,6 +921,10 @@ tdb_check_trustdb_stale (void) static int did_nextcheck=0; init_trustdb (); + + if (trustdb_args.no_trustdb) + return; /* No trustdb => can't be stale. */ + if (!did_nextcheck && (opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)) { @@ -931,6 +963,14 @@ tdb_get_validity_core (PKT_public_key *pk, PKT_user_id *uid, unsigned int validity; init_trustdb (); + + /* If we have no trustdb (which also means it has not been created) + and the trust-model is always, we don't know the validity - + return immediately. If we won't do that the tdbio code would try + to open the trustdb and run into a fatal error. */ + if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) + return TRUST_UNKNOWN; + check_trustdb_stale(); if(opt.trust_model==TM_DIRECT) commit dfb25d47a9fcfd7c7c084ea58744724cd5315086 Author: Werner Koch Date: Fri Oct 4 18:34:56 2013 +0200 gpg: Print a "not found" message for an unknown key in --key-edit. * g10/keyedit.c (keyedit_menu): Print message. -- GnuPG-bug-id: 1420 Signed-off-by: Werner Koch (cherry picked from commit 0bf54e60d31389812d05c3fd29bece876204561d) Resolved conflicts: g10/keyedit.c: Fix white spaces diff --git a/g10/keyedit.c b/g10/keyedit.c index 2b8b582..47a2234 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1506,7 +1506,10 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, /* Get the public key */ err = get_pubkey_byname (ctrl, NULL, NULL, username, &keyblock, &kdbhd, 1, 1); if (err) - goto leave; + { + log_error (_("key \"%s\" not found: %s\n"), username, gpg_strerror (err)); + goto leave; + } if (fix_keyblock (keyblock)) modified++; if (collapse_uids (&keyblock)) commit db1f74ba5338f624f146a3cb41a346e46b15c8f9 Author: Werner Koch Date: Fri Oct 4 13:44:39 2013 +0200 gpg: Protect against rogue keyservers sending secret keys. * g10/options.h (IMPORT_NO_SECKEY): New. * g10/keyserver.c (keyserver_spawn, keyserver_import_cert): Set new flag. * g10/import.c (import_secret_one): Deny import if flag is set. -- By modifying a keyserver or a DNS record to send a secret key, an attacker could trick a user into signing using a different key and user id. The trust model should protect against such rogue keys but we better make sure that secret keys are never received from remote sources. Suggested-by: Stefan Tomanek Signed-off-by: Werner Koch (cherry picked from commit e7abed3448c1c1a4e756c12f95b665b517d22ebe) Resolved conflicts: g10/import.c g10/keyserver.c diff --git a/g10/import.c b/g10/import.c index 74443ef..c3ad536 100644 --- a/g10/import.c +++ b/g10/import.c @@ -1563,6 +1563,12 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, } stats->secret_read++; + if ((options & IMPORT_NO_SECKEY)) + { + log_error (_("importing secret keys not allowed\n")); + return 0; + } + if (!uidnode) { log_error( _("key %s: no user ID\n"), keystr_from_pk (pk)); diff --git a/g10/keyserver.c b/g10/keyserver.c index 4de56fc..28b4a10 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -1578,11 +1578,14 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, harmless to ignore them, but ignoring them does make gpg complain about "no valid OpenPGP data found". One way to do this could be to continue parsing this line-by-line and make - a temp iobuf for each key. */ + a temp iobuf for each key. Note that we don't allow the + import of secret keys from a keyserver. Keyservers should + never accept or send them but we better protect against rogue + keyservers. */ import_keys_es_stream (ctrl, datastream, stats_handle, NULL, NULL, - opt.keyserver_options.import_options); - + (opt.keyserver_options.import_options + | IMPORT_NO_SECKEY)); import_print_stats (stats_handle); import_release_stats_handle (stats_handle); } @@ -1721,7 +1724,8 @@ keyserver_import_cert (ctrl_t ctrl, opt.no_armor=1; err = import_keys_es_stream (ctrl, key, NULL, fpr, fpr_len, - opt.keyserver_options.import_options); + (opt.keyserver_options.import_options + | IMPORT_NO_SECKEY)); opt.no_armor=armor_status; diff --git a/g10/options.h b/g10/options.h index 15ae412..47b8bfb 100644 --- a/g10/options.h +++ b/g10/options.h @@ -324,6 +324,7 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode; #define IMPORT_MERGE_ONLY (1<<4) #define IMPORT_MINIMAL (1<<5) #define IMPORT_CLEAN (1<<6) +#define IMPORT_NO_SECKEY (1<<7) #define EXPORT_LOCAL_SIGS (1<<0) #define EXPORT_ATTRIBUTES (1<<1) commit 90688b29f3701f4d3e2a5a49c5544fe8d2a84b2d Author: Werner Koch Date: Mon Aug 19 11:44:59 2013 +0200 agent: Fix UPDATESTARTUPTTY for ssh. * agent/command-ssh.c (setup_ssh_env): Fix env setting. -- gniibe reported this to gnupg-devel on 2012-07-04: [...] (2) UPDATESTARTUPTTY doesn't work to switch TTY for pinentry for SSH. [...] Current implementation: In the function start_command_handler_ssh, the logic puts priority on ctrl->session_env which is initialized by agent_init_default_ctrl. There are always GPG_TTY and TERM defined, because lines around 968 in gpg-agent.c, it says: /* Make sure that we have a default ttyname. */ While UPDATESTARTUPTTY updates opt.startup_env, it doesn't affect at all. Here is a patch to point the issue. Tested and works for me. Signed-off-by: Werner Koch (cherry picked from commit 9f5578c29adba6d4f7d3650121d07322c2f8d254) diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 4bd1aa7..4191d6f 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -3370,8 +3370,7 @@ setup_ssh_env (ctrl_t ctrl) const char *value; for (idx=0; !err && names[idx]; idx++) - if (!session_env_getenv (ctrl->session_env, names[idx]) - && (value = session_env_getenv (opt.startup_env, names[idx]))) + if ((value = session_env_getenv (opt.startup_env, names[idx]))) err = session_env_setenv (ctrl->session_env, names[idx], value); if (!err && !ctrl->lc_ctype && opt.startup_lc_ctype) commit 7c4bfa599fa69c3a942c8deea83737a4c5a0806e Author: Werner Koch Date: Mon Aug 19 11:22:11 2013 +0200 gpgv: Init Libgcrypt to avoid syslog warning. * g10/gpgv.c (main): Check libgcrypt version and disable secure memory. -- GnuPG-bug-id: 1376 Signed-off-by: Werner Koch (cherry picked from commit 3966eb244518d5612385d35a5149f7164a9fb707) Resolved conflicts: g10/gpgv.c diff --git a/g10/gpgv.c b/g10/gpgv.c index debde9d..d79b899 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -151,11 +151,18 @@ main( int argc, char **argv ) i18n_init(); init_common_subsystems (&argc, &argv); + if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) ) + { + log_fatal ( _("%s is too old (need %s, have %s)\n"), "libgcrypt", + NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) ); + } + gcry_control (GCRYCTL_DISABLE_SECMEM, 0); + gnupg_init_signals (0, NULL); opt.command_fd = -1; /* no command fd */ opt.pgp2_workarounds = 1; - opt.keyserver_options.options|=KEYSERVER_AUTO_KEY_RETRIEVE; + opt.keyserver_options.options |= KEYSERVER_AUTO_KEY_RETRIEVE; opt.trust_model = TM_ALWAYS; opt.batch = 1; @@ -164,6 +171,7 @@ main( int argc, char **argv ) tty_no_terminal(1); tty_batchmode(1); dotlock_disable (); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); pargs.argc = &argc; pargs.argv = &argv; commit 5ca482d5f949444ffd453de158ee186ab07fc9b6 Author: Werner Koch Date: Tue Aug 6 10:31:54 2013 +0200 Improve libcurl detection. * m4/libcurl.m4: Do not use AC_PATH_PROG if --with-libcurl as been given. Suggested by John Marshall. -- GnuPG-bug-id: 1510 (cherry picked from commit 110b52fffa77b339e6d59eba939408f7e87e7138) diff --git a/m4/libcurl.m4 b/m4/libcurl.m4 index 7d1dbd3..f6a631b 100644 --- a/m4/libcurl.m4 +++ b/m4/libcurl.m4 @@ -71,7 +71,11 @@ AC_DEFUN([LIBCURL_CHECK_CONFIG], if test -d "$_libcurl_with" ; then LIBCURL_CPPFLAGS="-I$withval/include" _libcurl_ldflags="-L$withval/lib" - AC_PATH_PROG([_libcurl_config],["$withval/bin/curl-config"]) + if test -x "$withval/bin/curl-config" ; then + _libcurl_config="$withval/bin/curl-config" + else + _libcurl_config= + fi else AC_PATH_PROG([_libcurl_config],[curl-config]) fi commit 0ab752cc2d46bbd0077bed889676169b7aeb1eb6 Author: Werner Koch Date: Tue Aug 6 10:04:12 2013 +0200 gpg: Remove legacy keyserver examples from the template conf file. * g10/options.skel: Update. (cherry picked from commit f3c5cc8bcd37e38b5d65db6a50466e22d03d1f0c) diff --git a/g10/options.skel b/g10/options.skel index 87bbd4e..9303f79 100644 --- a/g10/options.skel +++ b/g10/options.skel @@ -101,14 +101,9 @@ require-cross-certification # # Example HKP keyservers: # hkp://keys.gnupg.net -# hkp://subkeys.pgp.net -# -# Example email keyserver: -# mailto:pgp-public-keys at keys.pgp.net # # Example LDAP keyservers: # ldap://pgp.surfnet.nl:11370 -# ldap://keyserver.pgp.com # # Regular URL syntax applies, and you can set an alternate port # through the usual method: @@ -131,8 +126,6 @@ require-cross-certification keyserver hkp://keys.gnupg.net #keyserver http://http-keys.gnupg.net #keyserver mailto:pgp-public-keys at keys.nl.pgp.net -#keyserver ldap://pgp.surfnet.nl:11370 -#keyserver ldap://keyserver.pgp.com # Common options for keyserver functions: # commit 76b1940ad6f5f058c4a6bec35902da9f6d4e27b0 Author: Werner Koch Date: Fri Mar 7 09:46:44 2014 +0100 w32: Define WINVER only if needed. * common/sysutils.c (WINVER): Define only if less that 5.0. diff --git a/common/sysutils.c b/common/sysutils.c index a00cd94..f0c2ad8 100644 --- a/common/sysutils.c +++ b/common/sysutils.c @@ -54,7 +54,9 @@ # include #endif #ifdef HAVE_W32_SYSTEM -# define WINVER 0x0500 /* Required for AllowSetForegroundWindow. */ +# if WINVER < 0x0500 +# define WINVER 0x0500 /* Required for AllowSetForegroundWindow. */ +# endif # include #endif #ifdef HAVE_NPTH commit 63b7658a29809249d7aeb0423bf8c5a693eee0c7 Author: Werner Koch Date: Thu Aug 1 14:02:50 2013 +0200 w32: Remove unused code. * jnlib/w32-reg.c (write_w32_registry_string): Remove. diff --git a/common/w32-reg.c b/common/w32-reg.c index 3ef7a0a..428705c 100644 --- a/common/w32-reg.c +++ b/common/w32-reg.c @@ -223,102 +223,4 @@ read_w32_registry_string (const char *root, const char *dir, const char *name) } -/* Note: This code is not well tested. However, it is not used in - GnuPG. */ -#if 0 -int -write_w32_registry_string (const char *root, const char *dir, - const char *name, const char *value) -{ - HKEY root_key, reg_key; -#ifdef HAVE_W32CE_SYSTEM - wchar_t *wdir, *wname, *wvalue; - DWORD disp; - - if ( !(root_key = get_root_key(root) ) ) - return -1; - - wdir = utf8_to_wchar (dir); - if (!wdir) - return -1; - - if (RegOpenKeyEx (root_key, wdir, 0, 0, ®_key)) - { - jnlib_free (wdir); - return -1; - } - jnlib_free (wdir); - - if (name) - { - wname = utf8_to_wchar (name); - if (!wname) - return -1; - } - else - wname = NULL; - - wvalue = utf8_to_wchar (value); - if (wvalue) - { - jnlib_free (wname); - return -1; - } - - if (RegSetValueEx (reg_key, wname, 0, REG_SZ, - (BYTE *)wvalue, wcslen (wvalue)) != ERROR_SUCCESS ) - { - - if (RegCreateKeyEx (root_key, wname, 0, NULL, 0, 0, NULL, - ®_key, &disp) != ERROR_SUCCESS) - { - RegCloseKey(reg_key); - jnlib_free (wname); - jnlib_free (wvalue); - return -1; - } - if (RegSetValueEx (reg_key, wname, 0, REG_SZ, - (BYTE *)wvalue, wcslen (wvalue)) != ERROR_SUCCESS ) - { - RegCloseKey(reg_key); - jnlib_free (wname); - jnlib_free (wvalue); - return -1; - } - } - - jnlib_free (wname); - jnlib_free (wvalue); - RegCloseKey (reg_key); - return 0; -#else /*!HAVE_W32CE_SYSTEM*/ - - if ( !(root_key = get_root_key(root) ) ) - return -1; - - if ( RegOpenKeyEx( root_key, dir, 0, KEY_WRITE, ®_key ) - != ERROR_SUCCESS ) - return -1; - - if ( RegSetValueEx (reg_key, name, 0, REG_SZ, (BYTE *)value, - strlen( value ) ) != ERROR_SUCCESS ) - { - if ( RegCreateKey( root_key, name, ®_key ) != ERROR_SUCCESS ) - { - RegCloseKey(reg_key); - return -1; - } - if ( RegSetValueEx (reg_key, name, 0, REG_SZ, (BYTE *)value, - strlen( value ) ) != ERROR_SUCCESS ) - { - RegCloseKey(reg_key); - return -1; - } - } - - RegCloseKey (reg_key); - return 0; -#endif /*!HAVE_W32CE_SYSTEM*/ -} -#endif /*0*/ #endif /*HAVE_W32_SYSTEM*/ commit 9942a149ff2ab919c1b2916c7bc347e578a56b14 Author: Werner Koch Date: Wed Jul 3 15:20:25 2013 +0200 agent: Make --allow-mark-trusted the default. * agent/gpg-agent.c (opts, main): Add option --no-allow-mark-trusted. Put this option into the gpgconf-list. (main): Enable opt.allow_mark_trusted by default. * tools/gpgconf-comp.c (gc_options_gpg_agent): Replace allow-mark-trusted by no-allow-mark-trusted. * agent/trustlist.c (agent_marktrusted): Always set the "relax" flag. -- These changes have been in effect for the Gpg4win Windows version since 2011-01-24 and thus first released with Gpg4win 2.1.0. Given the current state of PKIX it does not make any sense to lure the Unix user into false security by making it harder to trust self-signed or CAcert certificates. Signed-off-by: Werner Koch (cherry picked from commit 90b419f3e9d05e509348d047e05fcc79e87be6cf) Resolved conflicts: NEWS agent/gpg-agent.c diff --git a/NEWS b/NEWS index 0c02a90..2efc395 100644 --- a/NEWS +++ b/NEWS @@ -6,8 +6,14 @@ Noteworthy changes in version 2.1.0-betaN (unreleased) * The GNU Pth library has been replaced by the new nPth library. - * New option --enable-putty-support to allow gpg-agent to act as a - Pageant replacement including full smartcard support. + * By default the users are now asked via the Pinentry whether they + trust an X.509 root key. To prohibit interactive marking of such + keys, the new option --no-allow-mark-trusted may be used. + + * The included ssh agent does now support ECDSA keys. + + * The new option --enable-putty-support allows gpg-agent on Windows + to act as a Pageant replacement with full smartcard support. * Removed support for the original HKP keyserver which is not anymore used by any site. diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 25750f2..87915d6 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -116,6 +116,7 @@ enum cmd_and_opt_values oIgnoreCacheForSigning, oAllowMarkTrusted, + oNoAllowMarkTrusted, oAllowPresetPassphrase, oAllowLoopbackPinentry, oKeepTTY, @@ -137,8 +138,8 @@ static ARGPARSE_OPTS opts[] = { { 301, NULL, 0, N_("@Options:\n ") }, - { oServer, "server", 0, N_("run in server mode (foreground)") }, { oDaemon, "daemon", 0, N_("run in daemon mode (background)") }, + { oServer, "server", 0, N_("run in server mode (foreground)") }, { oVerbose, "verbose", 0, N_("verbose") }, { oQuiet, "quiet", 0, N_("be somewhat more quiet") }, { oSh, "sh", 0, N_("sh-style command output") }, @@ -191,8 +192,9 @@ static ARGPARSE_OPTS opts[] = { { oIgnoreCacheForSigning, "ignore-cache-for-signing", 0, N_("do not use the PIN cache when signing")}, - { oAllowMarkTrusted, "allow-mark-trusted", 0, - N_("allow clients to mark keys as \"trusted\"")}, + { oNoAllowMarkTrusted, "no-allow-mark-trusted", 0, + N_("disallow clients to mark keys as \"trusted\"")}, + { oAllowMarkTrusted, "allow-mark-trusted", 0, "@"}, { oAllowPresetPassphrase, "allow-preset-passphrase", 0, N_("allow presetting passphrase")}, { oAllowLoopbackPinentry, "allow-loopback-pinentry", 0, @@ -523,7 +525,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) opt.max_passphrase_days = MAX_PASSPHRASE_DAYS; opt.enable_passhrase_history = 0; opt.ignore_cache_for_signing = 0; - opt.allow_mark_trusted = 0; + opt.allow_mark_trusted = 1; opt.disable_scdaemon = 0; disable_check_own_socket = 0; return 1; @@ -583,6 +585,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break; case oAllowMarkTrusted: opt.allow_mark_trusted = 1; break; + case oNoAllowMarkTrusted: opt.allow_mark_trusted = 0; break; case oAllowPresetPassphrase: opt.allow_preset_passphrase = 1; break; @@ -1008,7 +1011,7 @@ main (int argc, char **argv ) GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME); es_printf ("ignore-cache-for-signing:%lu:\n", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME); - es_printf ("allow-mark-trusted:%lu:\n", + es_printf ("no-allow-mark-trusted:%lu:\n", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME); es_printf ("disable-scdaemon:%lu:\n", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME); diff --git a/agent/trustlist.c b/agent/trustlist.c index 7829f01..e8f8fff 100644 --- a/agent/trustlist.c +++ b/agent/trustlist.c @@ -774,7 +774,8 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag) } else es_fputs (nameformatted, fp); - es_fprintf (fp, "\n%s%s %c\n", yes_i_trust?"":"!", fprformatted, flag); + es_fprintf (fp, "\n%s%s %c%s\n", yes_i_trust?"":"!", fprformatted, flag, + flag == 'S'? " relax":""); if (es_ferror (fp)) err = gpg_error_from_syserror (); diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index e97c7bd..4906994 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -542,8 +542,8 @@ static gc_option_t gc_options_gpg_agent[] = { "ignore-cache-for-signing", GC_OPT_FLAG_RUNTIME, GC_LEVEL_BASIC, "gnupg", "do not use the PIN cache when signing", GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT }, - { "allow-mark-trusted", GC_OPT_FLAG_RUNTIME, - GC_LEVEL_ADVANCED, "gnupg", "allow clients to mark keys as \"trusted\"", + { "no-allow-mark-trusted", GC_OPT_FLAG_RUNTIME, + GC_LEVEL_ADVANCED, "gnupg", "disallow clients to mark keys as \"trusted\"", GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT }, { "no-grab", GC_OPT_FLAG_RUNTIME, GC_LEVEL_EXPERT, "gnupg", "do not grab keyboard and mouse", commit 5105c8d2d344fd7301d456d8c13c7e90a54f7e98 Author: Werner Koch Date: Fri Mar 7 09:46:44 2014 +0100 ssh: Add support for Putty. * agent/gpg-agent.c [W32]: Include Several Windows header. (opts): Change help text for enable-ssh-support. (opts, main): Add option --enable-putty-support (putty_support, PUTTY_IPC_MAGIC, PUTTY_IPC_MAXLEN): New for W32. (agent_init_default_ctrl): Add and asssert call. (putty_message_proc, putty_message_thread): New. (handle_connections) [W32]: Start putty message thread. * common/sysutils.c (w32_get_user_sid): New for W32 only * tools/gpgconf-comp.c (gc_options_gpg_agent): Add --enable-ssh-support and --enable-putty-support. Make the configuration group visible at basic level. * agent/command-ssh.c (serve_mmapped_ssh_request): New for W32 only. -- This patch enables support for Putty. It has been tested with Putty 0.62 using an Unix created ssh key copied to the private-keys-v1.d directory on Windows and with a manually crafted sshcontrol file. It also works with a smartcard key. May thanks to gniibe who implemented a proxy in Python to test the putty/gpg-agent communication. Signed-off-by: Werner Koch (cherry picked from commit 9f32499f99a0817f63f7a73b09bdcebe60d4775d) Resolved conflicts: NEWS agent/agent.h agent/gpg-agent.c: Convert from pth to npth. common/sysutils.c common/sysutils.h diff --git a/NEWS b/NEWS index 7eb1fe9..0c02a90 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,9 @@ Noteworthy changes in version 2.1.0-betaN (unreleased) * The GNU Pth library has been replaced by the new nPth library. + * New option --enable-putty-support to allow gpg-agent to act as a + Pageant replacement including full smartcard support. + * Removed support for the original HKP keyserver which is not anymore used by any site. diff --git a/agent/agent.h b/agent/agent.h index d409300..eac7ba5 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -289,9 +289,14 @@ gpg_error_t agent_print_status (ctrl_t ctrl, const char *keyword, void bump_key_eventcounter (void); void bump_card_eventcounter (void); void start_command_handler (ctrl_t, gnupg_fd_t, gnupg_fd_t); -gpg_error_t pinentry_loopback(ctrl_t, const char *keyword, - unsigned char **buffer, size_t *size, - size_t max_length); +gpg_error_t pinentry_loopback (ctrl_t, const char *keyword, + unsigned char **buffer, size_t *size, + size_t max_length); + +#ifdef HAVE_W32_SYSTEM +int serve_mmapped_ssh_request (ctrl_t ctrl, + unsigned char *request, size_t maxreqlen); +#endif /*HAVE_W32_SYSTEM*/ /*-- command-ssh.c --*/ ssh_control_file_t ssh_open_control_file (void); diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 46aa94c..4bd1aa7 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -3443,3 +3443,149 @@ start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client) if (stream_sock) es_fclose (stream_sock); } + + +#ifdef HAVE_W32_SYSTEM +/* Serve one ssh-agent request. This is used for the Putty support. + REQUEST is the the mmapped memory which may be accessed up to a + length of MAXREQLEN. Returns 0 on success which also indicates + that a valid SSH response message is now in REQUEST. */ +int +serve_mmapped_ssh_request (ctrl_t ctrl, + unsigned char *request, size_t maxreqlen) +{ + gpg_error_t err; + int send_err = 0; + int valid_response = 0; + ssh_request_spec_t *spec; + u32 msglen; + estream_t request_stream, response_stream; + + if (setup_ssh_env (ctrl)) + goto leave; /* Error setting up the environment. */ + + if (maxreqlen < 5) + goto leave; /* Caller error. */ + + msglen = uint32_construct (request[0], request[1], request[2], request[3]); + if (msglen < 1 || msglen > maxreqlen - 4) + { + log_error ("ssh message len (%u) out of range", (unsigned int)msglen); + goto leave; + } + + spec = request_spec_lookup (request[4]); + if (!spec) + { + send_err = 1; /* Unknown request type. */ + goto leave; + } + + /* Create a stream object with the data part of the request. */ + if (spec->secret_input) + request_stream = es_mopen (NULL, 0, 0, 1, realloc_secure, gcry_free, "r+"); + else + request_stream = es_mopen (NULL, 0, 0, 1, gcry_realloc, gcry_free, "r+"); + if (!request_stream) + { + err = gpg_error_from_syserror (); + goto leave; + } + /* We have to disable the estream buffering, because the estream + core doesn't know about secure memory. */ + if (es_setvbuf (request_stream, NULL, _IONBF, 0)) + { + err = gpg_error_from_syserror (); + goto leave; + } + /* Copy the request to the stream but omit the request type. */ + err = stream_write_data (request_stream, request + 5, msglen - 1); + if (err) + goto leave; + es_rewind (request_stream); + + response_stream = es_fopenmem (0, "r+b"); + if (!response_stream) + { + err = gpg_error_from_syserror (); + goto leave; + } + + if (opt.verbose) + log_info ("ssh request handler for %s (%u) started\n", + spec->identifier, spec->type); + + err = (*spec->handler) (ctrl, request_stream, response_stream); + + if (opt.verbose) + { + if (err) + log_info ("ssh request handler for %s (%u) failed: %s\n", + spec->identifier, spec->type, gpg_strerror (err)); + else + log_info ("ssh request handler for %s (%u) ready\n", + spec->identifier, spec->type); + } + + es_fclose (request_stream); + request_stream = NULL; + + if (err) + { + send_err = 1; + goto leave; + } + + /* Put the response back into the mmapped buffer. */ + { + void *response_data; + size_t response_size; + + /* NB: In contrast to the request-stream, the response stream + includes the the message type byte. */ + if (es_fclose_snatch (response_stream, &response_data, &response_size)) + { + log_error ("snatching ssh response failed: %s", + gpg_strerror (gpg_error_from_syserror ())); + send_err = 1; /* Ooops. */ + goto leave; + } + + if (opt.verbose > 1) + log_info ("sending ssh response of length %u\n", + (unsigned int)response_size); + if (response_size > maxreqlen - 4) + { + log_error ("invalid length of the ssh response: %s", + gpg_strerror (GPG_ERR_INTERNAL)); + es_free (response_data); + send_err = 1; + goto leave; + } + + request[0] = response_size >> 24; + request[1] = response_size >> 16; + request[2] = response_size >> 8; + request[3] = response_size >> 0; + memcpy (request+4, response_data, response_size); + es_free (response_data); + valid_response = 1; + } + + leave: + if (send_err) + { + request[0] = 0; + request[1] = 0; + request[2] = 0; + request[3] = 1; + request[4] = SSH_RESPONSE_FAILURE; + valid_response = 1; + } + + /* Reset the SCD in case it has been used. */ + agent_reset_scd (ctrl); + + return valid_response? 0 : -1; +} +#endif /*HAVE_W32_SYSTEM*/ diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index c53566b..25750f2 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -1,6 +1,7 @@ /* gpg-agent.c - The GnuPG Agent * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, * 2010 Free Software Foundation, Inc. + * Copyright (C) 2013 Werner Koch * * This file is part of GnuPG. * @@ -30,7 +31,16 @@ #include #include #include -#ifndef HAVE_W32_SYSTEM +#ifdef HAVE_W32_SYSTEM +# ifndef WINVER +# define WINVER 0x0500 /* Same as in common/sysutils.c */ +# endif +# ifdef HAVE_WINSOCK2_H +# include +# endif +# include +# include +#else /*!HAVE_W32_SYSTEM*/ # include # include #endif /*!HAVE_W32_SYSTEM*/ @@ -111,6 +121,7 @@ enum cmd_and_opt_values oKeepTTY, oKeepDISPLAY, oSSHSupport, + oPuttySupport, oDisableScdaemon, oDisableCheckOwnSocket, oWriteEnvFile @@ -186,7 +197,14 @@ static ARGPARSE_OPTS opts[] = { N_("allow presetting passphrase")}, { oAllowLoopbackPinentry, "allow-loopback-pinentry", 0, N_("allow presetting passphrase")}, - { oSSHSupport, "enable-ssh-support", 0, N_("enable ssh-agent emulation") }, + { oSSHSupport, "enable-ssh-support", 0, N_("enable ssh support") }, + { oPuttySupport, "enable-putty-support", 0, +#ifdef HAVE_W32_SYSTEM + N_("enable putty support") +#else + "@" +#endif + }, { oWriteEnvFile, "write-env-file", 2|8, N_("|FILE|write environment settings also to FILE")}, {0} @@ -218,6 +236,17 @@ static ARGPARSE_OPTS opts[] = { #endif +#ifdef HAVE_W32_SYSTEM +/* Flag indicating that support for Putty has been enabled. */ +static int putty_support; +/* A magic value used with WM_COPYDATA. */ +#define PUTTY_IPC_MAGIC 0x804e50ba +/* To avoid surprises we limit the size of the mapped IPC file to this + value. Putty currently (0.62) uses 8k, thus 16k should be enough + for the foreseeable future. */ +#define PUTTY_IPC_MAXLEN 16384 +#endif /*HAVE_W32_SYSTEM*/ + /* The list of open file descriptors at startup. Note that this list has been allocated using the standard malloc. */ static int *startup_fd_list; @@ -815,6 +844,13 @@ main (int argc, char **argv ) case oKeepDISPLAY: opt.keep_display = 1; break; case oSSHSupport: opt.ssh_support = 1; break; + case oPuttySupport: +# ifdef HAVE_W32_SYSTEM + putty_support = 1; + opt.ssh_support = 1; +# endif + break; + case oWriteEnvFile: if (pargs.r_type) env_file_name = pargs.r.ret_str; @@ -976,6 +1012,11 @@ main (int argc, char **argv ) GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME); es_printf ("disable-scdaemon:%lu:\n", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME); +#ifdef HAVE_W32_SYSTEM + es_printf ("enable-putty-support:%lu:\n", GC_OPT_FLAG_NONE); +#else + es_printf ("enable-ssh-support:%lu:\n", GC_OPT_FLAG_NONE); +#endif agent_exit (0); } @@ -1311,6 +1352,8 @@ agent_exit (int rc) static void agent_init_default_ctrl (ctrl_t ctrl) { + assert (ctrl->session_env); + /* Note we ignore malloc errors because we can't do much about it and the request will fail anyway shortly after this initialization. */ @@ -1328,7 +1371,6 @@ agent_init_default_ctrl (ctrl_t ctrl) xfree (ctrl->lc_messages); ctrl->lc_messages = default_lc_messages? xtrystrdup (default_lc_messages) /**/ : NULL; - ctrl->cache_ttl_opt_preset = CACHE_TTL_OPT_PRESET; } @@ -1820,6 +1862,196 @@ check_nonce (ctrl_t ctrl, assuan_sock_nonce_t *nonce) } +#ifdef HAVE_W32_SYSTEM +/* The window message processing function for Putty. Warning: This + code runs as a native Windows thread. Use of our own functions + needs to be bracket with pth_leave/pth_enter. */ +static LRESULT CALLBACK +putty_message_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + int ret = 0; + int w32rc; + COPYDATASTRUCT *cds; + const char *mapfile; + HANDLE maphd; + PSID mysid = NULL; + PSID mapsid = NULL; + void *data = NULL; + PSECURITY_DESCRIPTOR psd = NULL; + ctrl_t ctrl = NULL; + + if (msg != WM_COPYDATA) + { + return DefWindowProc (hwnd, msg, wparam, lparam); + } + + cds = (COPYDATASTRUCT*)lparam; + if (cds->dwData != PUTTY_IPC_MAGIC) + return 0; /* Ignore data with the wrong magic. */ + mapfile = cds->lpData; + if (!cds->cbData || mapfile[cds->cbData - 1]) + return 0; /* Ignore empty and non-properly terminated strings. */ + + if (DBG_ASSUAN) + { + npth_protect (); + log_debug ("ssh map file '%s'", mapfile); + npth_unprotect (); + } + + maphd = OpenFileMapping (FILE_MAP_ALL_ACCESS, FALSE, mapfile); + if (DBG_ASSUAN) + { + npth_protect (); + log_debug ("ssh map handle %p\n", maphd); + npth_unprotect (); + } + + if (!maphd || maphd == INVALID_HANDLE_VALUE) + return 0; + + npth_protect (); + + mysid = w32_get_user_sid (); + if (!mysid) + { + log_error ("error getting my sid\n"); + goto leave; + } + + w32rc = GetSecurityInfo (maphd, SE_KERNEL_OBJECT, + OWNER_SECURITY_INFORMATION, + &mapsid, NULL, NULL, NULL, + &psd); + if (w32rc) + { + log_error ("error getting sid of ssh map file: rc=%d", w32rc); + goto leave; + } + + if (DBG_ASSUAN) + { + char *sidstr; + + if (!ConvertSidToStringSid (mysid, &sidstr)) + sidstr = NULL; + log_debug (" my sid: '%s'", sidstr? sidstr: "[error]"); + LocalFree (sidstr); + if (!ConvertSidToStringSid (mapsid, &sidstr)) + sidstr = NULL; + log_debug ("ssh map file sid: '%s'", sidstr? sidstr: "[error]"); + LocalFree (sidstr); + } + + if (!EqualSid (mysid, mapsid)) + { + log_error ("ssh map file has a non-matching sid\n"); + goto leave; + } + + data = MapViewOfFile (maphd, FILE_MAP_ALL_ACCESS, 0, 0, 0); + if (DBG_ASSUAN) + log_debug ("ssh IPC buffer at %p\n", data); + if (!data) + goto leave; + + /* log_printhex ("request:", data, 20); */ + + ctrl = xtrycalloc (1, sizeof *ctrl); + if (!ctrl) + { + log_error ("error allocating connection control data: %s\n", + strerror (errno) ); + goto leave; + } + ctrl->session_env = session_env_new (); + if (!ctrl->session_env) + { + log_error ("error allocating session environment block: %s\n", + strerror (errno) ); + goto leave; + } + + agent_init_default_ctrl (ctrl); + if (!serve_mmapped_ssh_request (ctrl, data, PUTTY_IPC_MAXLEN)) + ret = 1; /* Valid ssh message has been constructed. */ + agent_deinit_default_ctrl (ctrl); + /* log_printhex (" reply:", data, 20); */ + + leave: + xfree (ctrl); + if (data) + UnmapViewOfFile (data); + xfree (mapsid); + if (psd) + LocalFree (psd); + xfree (mysid); + CloseHandle (maphd); + + npth_unprotect (); + + return ret; +} +#endif /*HAVE_W32_SYSTEM*/ + + +#ifdef HAVE_W32_SYSTEM +/* The thread handling Putty's IPC requests. */ +static void * +putty_message_thread (void *arg) +{ + WNDCLASS wndwclass = {0, putty_message_proc, 0, 0, + NULL, NULL, NULL, NULL, NULL, "Pageant"}; + HWND hwnd; + MSG msg; + + (void)arg; + + if (opt.verbose) + log_info ("putty message loop thread started\n"); + + /* The message loop runs as thread independent from our nPth system. + This also means that we need to make sure that we switch back to + our system before calling any no-windows function. */ + npth_unprotect (); + + /* First create a window to make sure that a message queue exists + for this thread. */ + if (!RegisterClass (&wndwclass)) + { + npth_protect (); + log_error ("error registering Pageant window class"); + return NULL; + } + hwnd = CreateWindowEx (0, "Pageant", "Pageant", 0, + 0, 0, 0, 0, + HWND_MESSAGE, /* hWndParent */ + NULL, /* hWndMenu */ + NULL, /* hInstance */ + NULL); /* lpParm */ + if (!hwnd) + { + npth_protect (); + log_error ("error creating Pageant window"); + return NULL; + } + + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + /* Back to nPth. */ + npth_protect (); + + if (opt.verbose) + log_info ("putty message loop thread stopped\n"); + return NULL; +} +#endif /*HAVE_W32_SYSTEM*/ + + /* This is the standard connection thread's main function. */ static void * start_connection_thread (void *arg) @@ -1920,6 +2152,22 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh) # endif #endif + /* On Windows we need to fire up a separate thread to listen for + requests from Putty (an SSH client), so we can replace Putty's + Pageant (its ssh-agent implementation). */ +#ifdef HAVE_W32_SYSTEM + if (putty_support) + { + npth_t thread; + + ret = npth_create (&thread, &tattr, putty_message_thread, NULL); + if (ret) + { + log_error ("error spawning putty message loop: %s\n", strerror (ret)); + } + } +#endif /*HAVE_W32_SYSTEM*/ + /* Set a flag to tell call-scd.c that it may enable event notifications. */ opt.sigusr2_enabled = 1; diff --git a/common/sysutils.c b/common/sysutils.c index f57dcc1..a00cd94 100644 --- a/common/sysutils.c +++ b/common/sysutils.c @@ -1,6 +1,7 @@ /* sysutils.c - system helpers * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, * 2007, 2008 Free Software Foundation, Inc. + * Copyright (C) 2013 Werner Koch * * This file is part of GnuPG. * @@ -688,3 +689,59 @@ _gnupg_getenv (const char *name) } #endif /*HAVE_W32CE_SYSTEM*/ + + +#ifdef HAVE_W32_SYSTEM +/* Return the user's security identifier from the current process. */ +PSID +w32_get_user_sid (void) +{ + int okay = 0; + HANDLE proc = NULL; + HANDLE token = NULL; + TOKEN_USER *user = NULL; + PSID sid = NULL; + DWORD tokenlen, sidlen; + + proc = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId()); + if (!proc) + goto leave; + + if (!OpenProcessToken (proc, TOKEN_QUERY, &token)) + goto leave; + + if (!GetTokenInformation (token, TokenUser, NULL, 0, &tokenlen) + && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + goto leave; + + user = xtrymalloc (tokenlen); + if (!user) + goto leave; + + if (!GetTokenInformation (token, TokenUser, user, tokenlen, &tokenlen)) + goto leave; + if (!IsValidSid (user->User.Sid)) + goto leave; + sidlen = GetLengthSid (user->User.Sid); + sid = xtrymalloc (sidlen); + if (!sid) + goto leave; + if (!CopySid (sidlen, sid, user->User.Sid)) + goto leave; + okay = 1; + + leave: + xfree (user); + if (token) + CloseHandle (token); + if (proc) + CloseHandle (proc); + + if (!okay) + { + xfree (sid); + sid = NULL; + } + return sid; +} +#endif /*HAVE_W32_SYSTEM*/ diff --git a/common/sysutils.h b/common/sysutils.h index 5faa7b3..da2c250 100644 --- a/common/sysutils.h +++ b/common/sysutils.h @@ -65,6 +65,7 @@ int gnupg_setenv (const char *name, const char *value, int overwrite); int gnupg_unsetenv (const char *name); #ifdef HAVE_W32_SYSTEM +void *w32_get_user_sid (void); #include "../common/w32help.h" diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index dda4c9a..e97c7bd 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -492,7 +492,7 @@ static gc_option_t gc_options_gpg_agent[] = GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT }, { "Configuration", - GC_OPT_FLAG_GROUP, GC_LEVEL_EXPERT, + GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC, "gnupg", N_("Options controlling the configuration") }, { "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT, "gnupg", "|FILE|read options from FILE", @@ -500,6 +500,12 @@ static gc_option_t gc_options_gpg_agent[] = { "disable-scdaemon", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED, "gnupg", "do not use the SCdaemon", GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT }, + { "enable-ssh-support", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC, + "gnupg", "enable ssh support", + GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT }, + { "enable-putty-support", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC, + "gnupg", "enable putty support", + GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT }, { "Debug", GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED, commit 179012ddd48e63ca83e8f5c24537a2db45c3e122 Author: Werner Koch Date: Wed Jul 3 13:10:29 2013 +0200 agent: Fix binary vs. text mode problem in ssh. * agent/command-ssh.c (file_to_buffer) (ssh_handler_request_identities): Open streams in binary mode. (start_command_handler_ssh): Factor some code out to .. (setup_ssh_env): new function. -- This is for now a theoretical fix because there is no ssh client yet which uses the GnuPG style IPC. OpenSSL for Cygwin uses only a quite similar one. gniibe suggested to implement that IPC style in Libassuan so that a Cygwin version of OpenSSL may be used with GnuPG. Signed-off-by: Werner Koch (cherry picked from commit ed056d67c7c93306b68829f83a2565e978dcfd9b) Also fixed one typo. diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 8f8e285..46aa94c 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -684,7 +684,7 @@ file_to_buffer (const char *filename, unsigned char **buffer, size_t *buffer_n) buffer_new = NULL; err = 0; - stream = es_fopen (filename, "r"); + stream = es_fopen (filename, "rb"); if (! stream) { err = gpg_error_from_syserror (); @@ -2281,7 +2281,7 @@ ssh_handler_request_identities (ctrl_t ctrl, key_counter = 0; err = 0; - key_blobs = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+"); + key_blobs = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+b"); if (! key_blobs) { err = gpg_error_from_syserror (); @@ -3356,44 +3356,51 @@ ssh_request_process (ctrl_t ctrl, estream_t stream_sock) return !!err; } -/* Start serving client on SOCK_CLIENT. */ -void -start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client) + +/* Because the ssh protocol does not send us information about the + current TTY setting, we use this function to use those from startup + or those explictly set. */ +static gpg_error_t +setup_ssh_env (ctrl_t ctrl) { - estream_t stream_sock = NULL; + static const char *names[] = + {"GPG_TTY", "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL}; gpg_error_t err = 0; - int ret; + int idx; + const char *value; - /* Because the ssh protocol does not send us information about the - the current TTY setting, we resort here to use those from startup - or those explictly set. */ - { - static const char *names[] = - {"GPG_TTY", "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL}; - int idx; - const char *value; + for (idx=0; !err && names[idx]; idx++) + if (!session_env_getenv (ctrl->session_env, names[idx]) + && (value = session_env_getenv (opt.startup_env, names[idx]))) + err = session_env_setenv (ctrl->session_env, names[idx], value); - for (idx=0; !err && names[idx]; idx++) - if (!session_env_getenv (ctrl->session_env, names[idx]) - && (value = session_env_getenv (opt.startup_env, names[idx]))) - err = session_env_setenv (ctrl->session_env, names[idx], value); + if (!err && !ctrl->lc_ctype && opt.startup_lc_ctype) + if (!(ctrl->lc_ctype = xtrystrdup (opt.startup_lc_ctype))) + err = gpg_error_from_syserror (); - if (!err && !ctrl->lc_ctype && opt.startup_lc_ctype) - if (!(ctrl->lc_ctype = xtrystrdup (opt.startup_lc_ctype))) - err = gpg_error_from_syserror (); + if (!err && !ctrl->lc_messages && opt.startup_lc_messages) + if (!(ctrl->lc_messages = xtrystrdup (opt.startup_lc_messages))) + err = gpg_error_from_syserror (); - if (!err && !ctrl->lc_messages && opt.startup_lc_messages) - if (!(ctrl->lc_messages = xtrystrdup (opt.startup_lc_messages))) - err = gpg_error_from_syserror (); + if (err) + log_error ("error setting default session environment: %s\n", + gpg_strerror (err)); - if (err) - { - log_error ("error setting default session environment: %s\n", - gpg_strerror (err)); - goto out; - } - } + return err; +} + + +/* Start serving client on SOCK_CLIENT. */ +void +start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client) +{ + estream_t stream_sock = NULL; + gpg_error_t err; + int ret; + err = setup_ssh_env (ctrl); + if (err) + goto out; /* Create stream from socket. */ stream_sock = es_fdopen (FD2INT(sock_client), "r+"); commit 4ad123d6fe341da7768e43360375e17fa89e8e0d Author: Werner Koch Date: Thu Apr 25 12:00:16 2013 +0100 Fix syntax error for building on APPLE. * scd/pcsc-wrapper.c [__APPLE__]: Fix syntax error. -- For W32 and probably for Cygwin we don't need the wrapper, thus the problems does not exhibit itself. (cherry picked from commit 8ddf604659b93754ffa6dea295678a8adc293f90) diff --git a/scd/pcsc-wrapper.c b/scd/pcsc-wrapper.c index f39a5dd..e20e111 100644 --- a/scd/pcsc-wrapper.c +++ b/scd/pcsc-wrapper.c @@ -66,7 +66,7 @@ static int verbose; #if defined(__APPLE__) || defined(_WIN32) || defined(__CYGWIN__) -typedef unsinged int pcsc_dword_t; +typedef unsigned int pcsc_dword_t; #else typedef unsigned long pcsc_dword_t; #endif commit d2a6be24af0bf220bb448fdd50c0196faddee0f4 Author: Werner Koch Date: Thu Apr 18 14:40:43 2013 +0200 Ignore obsolete option --disable-keypad. * scd/scdaemon.c (opts): Ignore --disable-keypad. -- The renaming of --disable-keypad to --disable-pinpad might mess up configuration files managed with a GUI. The GUI does not not anymore know about the old option and would allow the user to switch "disable-pinpad" on. However, a "disable-keypad" might still linger in the conf file with gpgconf not knowing about it. Thus the conf file would always be rejected and manual intervention would be required. Ignoring the old option nicely solves the problem. (cherry picked from commit e24e92d7e244edd578c0c1f0fba6e0070cb5f104) diff --git a/scd/scdaemon.c b/scd/scdaemon.c index daa4eea..982c52f 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -144,8 +144,11 @@ static ARGPARSE_OPTS opts[] = { /* end --disable-ccid */), ARGPARSE_s_u (oCardTimeout, "card-timeout", N_("|N|disconnect the card after N seconds of inactivity")), + ARGPARSE_s_n (oDisablePinpad, "disable-pinpad", N_("do not use a reader's pinpad")), + ARGPARSE_ignore (300, "disable-keypad"), + ARGPARSE_s_n (oAllowAdmin, "allow-admin", "@"), ARGPARSE_s_n (oDenyAdmin, "deny-admin", N_("deny the use of admin card commands")), commit 8fc9de8d6bf663f7c8419b42dab01f590a694d59 Author: Werner Koch Date: Thu Apr 18 14:40:43 2013 +0200 Allow marking options as ignored. * jnlib/argparse.h (ARGPARSE_OPT_IGNORE): New. (ARGPARSE_TYPE_MASK): New, for internal use. (ARGPARSE_ignore): New. * jnlib/argparse.c (optfile_parse, arg_parse): Replace remaining constants by macros. (optfile_parse): Implement ARGPARSE_OPT_IGNORE. (arg_parse): Exclide ignore options from --dump-options. -- In addition to the ignore-invalid-option (commit 41d56433) it is often useful to mark options in a configuration which as NOP. For example options which have no more function at all but can be expected to be found in existing conf files. Such an option (or command) may now be given as ARGPARSE_ignore (300, "obsolete-option") The 300 is merely used as a non-valid single option name much like group names or the 500+n values used for long options. Signed-off-by: Werner Koch (cherry picked from commit 54c54e2824aab5716a187bbbf6dff8860d6a6056) Resolved conflicts: common/argparse.c: Fixed. diff --git a/common/argparse.c b/common/argparse.c index fb3dbb6..6d18bd4 100644 --- a/common/argparse.c +++ b/common/argparse.c @@ -1,6 +1,7 @@ /* [argparse.c wk 17.06.97] Argument Parser for option handling * Copyright (C) 1998, 1999, 2000, 2001, 2006 * 2007, 2008, 2012 Free Software Foundation, Inc. + * Copyright (C) 1997, 2013 Werner Koch * * This file is part of JNLIB, which is a subsystem of GnuPG. * @@ -104,7 +105,8 @@ * 4 = takes ulong argument * Bit 3 : argument is optional (r_type will the be set to 0) * Bit 4 : allow 0x etc. prefixed values. - * Bit 7 : this is a command and not an option + * Bit 6 : Ignore this option + * Bit 7 : This is a command and not an option * You stop the option processing by setting opts to NULL, the function will * then return 0. * @Return Value @@ -128,6 +130,7 @@ * { 'o', "output", 2 }, * { 'c', "cross-ref", 2|8 }, * { 'm', "my-option", 1|8 }, + * { 300, "ignored-long-option, ARGPARSE_OP_IGNORE}, * { 500, "have-no-short-option-for-this-long-option", 0 }, * {0} }; * ARGPARSE_ARGS pargs = { &argc, &argv, 0 } @@ -482,7 +485,12 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno, } idx = i; arg->r_opt = opts[idx].short_opt; - if (!opts[idx].short_opt ) + if ((opts[idx].flags & ARGPARSE_OPT_IGNORE)) + { + state = i = 0; + continue; + } + else if (!opts[idx].short_opt ) { if (!strcmp (keyword, "ignore-invalid-option")) { @@ -500,9 +508,9 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno, ? ARGPARSE_INVALID_COMMAND : ARGPARSE_INVALID_OPTION); } - else if (!(opts[idx].flags & 7)) + else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) arg->r_type = 0; /* Does not take an arg. */ - else if ((opts[idx].flags & 8) ) + else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL) ) arg->r_type = 0; /* Arg is optional. */ else arg->r_opt = ARGPARSE_MISSING_ARG; @@ -514,9 +522,9 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno, /* No argument found. */ if (in_alias) arg->r_opt = ARGPARSE_MISSING_ARG; - else if (!(opts[idx].flags & 7)) + else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) arg->r_type = 0; /* Does not take an arg. */ - else if ((opts[idx].flags & 8)) + else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL)) arg->r_type = 0; /* No optional argument. */ else arg->r_opt = ARGPARSE_MISSING_ARG; @@ -552,7 +560,7 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno, } } } - else if (!(opts[idx].flags & 7)) + else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) arg->r_opt = ARGPARSE_UNEXPECTED_ARG; else { @@ -614,7 +622,11 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno, break; idx = i; arg->r_opt = opts[idx].short_opt; - if (!opts[idx].short_opt) + if ((opts[idx].flags & ARGPARSE_OPT_IGNORE)) + { + state = 1; /* Process like a comment. */ + } + else if (!opts[idx].short_opt) { if (!strcmp (keyword, "alias")) { @@ -849,7 +861,7 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) { for (i=0; opts[i].short_opt; i++ ) { - if ( opts[i].long_opt ) + if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE)) writestrings (0, "--", opts[i].long_opt, "\n", NULL); } writestrings (0, "--dump-options\n--help\n--version\n--warranty\n", @@ -868,7 +880,7 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) arg->r_opt = opts[i].short_opt; if ( i < 0 ) ; - else if ( (opts[i].flags & 0x07) ) + else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) ) { if ( argpos ) { @@ -952,7 +964,7 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) arg->internal.inarg++; /* Point to the next arg. */ arg->r.ret_str = s; } - else if ( (opts[i].flags & 7) ) + else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) ) { if ( s[1] && !dash_kludge ) { @@ -1024,9 +1036,9 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) static int set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s) { - int base = (flags & 16)? 0 : 10; + int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10; - switch ( (arg->r_type = (flags & 7)) ) + switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) ) { case ARGPARSE_TYPE_INT: arg->r.ret_int = (int)strtol(s,NULL,base); diff --git a/common/argparse.h b/common/argparse.h index a36218f..29c7b62 100644 --- a/common/argparse.h +++ b/common/argparse.h @@ -94,7 +94,10 @@ typedef struct #define ARGPARSE_TYPE_ULONG 4 /* Takes an unsigned long argument. */ #define ARGPARSE_OPT_OPTIONAL (1<<3) /* Argument is optional. */ #define ARGPARSE_OPT_PREFIX (1<<4) /* Allow 0x etc. prefixed values. */ -#define ARGPARSE_OPT_COMMAND (1<<8) /* The argument is a command. */ +#define ARGPARSE_OPT_IGNORE (1<<6) /* Ignore command or option. */ +#define ARGPARSE_OPT_COMMAND (1<<7) /* The argument is a command. */ + +#define ARGPARSE_TYPE_MASK 7 /* Mask for the type values (internal). */ /* A set of macros to make option definitions easier to read. */ #define ARGPARSE_x(s,l,t,f,d) \ @@ -161,6 +164,8 @@ typedef struct #define ARGPARSE_c(s,l,d) \ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_COMMAND), (d) } +#define ARGPARSE_ignore(s,l) \ + { (s), (l), (ARGPARSE_OPT_IGNORE), "@" } #define ARGPARSE_group(s,d) \ { (s), NULL, 0, (d) } ----------------------------------------------------------------------- Summary of changes: NEWS | 13 +++ agent/agent.h | 11 ++- agent/command-ssh.c | 216 ++++++++++++++++++++++++++++++++++------ agent/gpg-agent.c | 267 ++++++++++++++++++++++++++++++++++++++++++++++++-- agent/trustlist.c | 3 +- common/argparse.c | 38 ++++--- common/argparse.h | 7 +- common/estream.c | 10 +- common/sysutils.c | 61 +++++++++++- common/sysutils.h | 1 + common/w32-reg.c | 98 ------------------ g10/gpg.c | 6 +- g10/gpgv.c | 10 +- g10/import.c | 6 ++ g10/keyedit.c | 5 +- g10/keyserver.c | 12 ++- g10/options.h | 1 + g10/options.skel | 7 -- g10/tdbio.c | 8 +- g10/tdbio.h | 2 +- g10/trustdb.c | 68 ++++++++++--- m4/libcurl.m4 | 6 +- scd/pcsc-wrapper.c | 2 +- scd/scdaemon.c | 3 + tools/gpgconf-comp.c | 12 ++- 25 files changed, 672 insertions(+), 201 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Mon Mar 10 10:57:29 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Mon, 10 Mar 2014 10:57:29 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-341-gfeda379 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via feda379595e06583bc5b3610dec74890de29cb8e (commit) via 4387ecb11cdb2addf738eb922c1b9f14c6c76efc (commit) via 35266076e3452590931e58f188815859dff6de3c (commit) via 72133b54de89e593d8193b106e9369cf90d2e1c0 (commit) from 36372dcb2f75a659b7ace0e9c46f07bb431d009c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit feda379595e06583bc5b3610dec74890de29cb8e Author: Werner Koch Date: Fri Mar 7 09:46:44 2014 +0100 dirmmgr: Use a portability wrapper for struct timeval. * dirmngr/dirmngr_ldap.c [W32]: Include winber.h. (my_ldap_timeval_t): New. diff --git a/dirmngr/dirmngr_ldap.c b/dirmngr/dirmngr_ldap.c index 4e706d5..7d3bd17 100644 --- a/dirmngr/dirmngr_ldap.c +++ b/dirmngr/dirmngr_ldap.c @@ -37,14 +37,15 @@ #endif #ifdef HAVE_W32_SYSTEM -#include -#include -#include -#include "ldap-url.h" +# include +# include +# include +# include +# include "ldap-url.h" #else -/* For OpenLDAP, to enable the API that we're using. */ -#define LDAP_DEPRECATED 1 -#include + /* For OpenLDAP, to enable the API that we're using. */ +# define LDAP_DEPRECATED 1 +# include #endif @@ -97,6 +98,12 @@ static void npth_protect (void) { } # define my_ldap_free_attr(a) ldap_memfree ((a)) #endif +#ifdef HAVE_W32_SYSTEM + typedef LDAP_TIMEVAL my_ldap_timeval_t; +#else + typedef struct timeval my_ldap_timeval_t; +#endif + #define DEFAULT_LDAP_TIMEOUT 100 /* Arbitrary long timeout. */ @@ -154,7 +161,7 @@ struct my_opt_s { int quiet; int verbose; - struct timeval timeout; /* Timeout for the LDAP search functions. */ + my_ldap_timeval_t timeout;/* Timeout for the LDAP search functions. */ unsigned int alarm_timeout; /* And for the alarm based timeout. */ int multi; commit 4387ecb11cdb2addf738eb922c1b9f14c6c76efc Author: Werner Koch Date: Fri Mar 7 09:46:44 2014 +0100 Silence more warnings about unused vars and args. * dirmngr/cdblib.c (cdb_init) [W32]: Remove unused var. * dirmngr/dirmngr-client.c (start_dirmngr): s/int/assuan_fd_t/. * dirmngr/dirmngr.c (w32_service_control): Mark unused args. (call_real_main): New. (main) [W32]: Use new function to match prototype. (real_main) [W32]: Mark unused vars. (handle_signal) [W32]: Do not build the function at all. (handle_connections) [W32]: Do not define signo. * dirmngr/ldap-wrapper-ce.c (outstream_reader_cb): Remove used vars. * g10/tdbio.c (ftruncate) [DOSISH]: Define only if not yet defined. diff --git a/dirmngr/cdblib.c b/dirmngr/cdblib.c index 9ab4d3c..9636b6c 100644 --- a/dirmngr/cdblib.c +++ b/dirmngr/cdblib.c @@ -115,9 +115,10 @@ cdb_init(struct cdb *cdbp, int fd) { struct stat st; unsigned char *mem; - unsigned fsize; #ifdef _WIN32 HANDLE hFile, hMapping; +#else + unsigned int fsize; #endif /* get file size */ @@ -128,7 +129,6 @@ cdb_init(struct cdb *cdbp, int fd) gpg_err_set_errno (EPROTO); return -1; } - fsize = (unsigned)(st.st_size & 0xffffffffu); /* memory-map file */ #ifdef _WIN32 # ifdef __MINGW32CE__ @@ -145,11 +145,12 @@ cdb_init(struct cdb *cdbp, int fd) if (!mem) return -1; cdbp->cdb_mapping = hMapping; -#else +#else /*!_WIN32*/ + fsize = (unsigned int)(st.st_size & 0xffffffffu); mem = (unsigned char*)mmap(NULL, fsize, PROT_READ, MAP_SHARED, fd, 0); if (mem == MAP_FAILED) return -1; -#endif /* _WIN32 */ +#endif /*!_WIN32*/ cdbp->cdb_fd = fd; cdbp->cdb_fsize = st.st_size; diff --git a/dirmngr/dirmngr-client.c b/dirmngr/dirmngr-client.c index 76f4710..da97443 100644 --- a/dirmngr/dirmngr-client.c +++ b/dirmngr/dirmngr-client.c @@ -459,7 +459,7 @@ start_dirmngr (int only_daemon) { const char *pgmname; const char *argv[3]; - int no_close_list[3]; + assuan_fd_t no_close_list[3]; int i; if (only_daemon) @@ -486,7 +486,7 @@ start_dirmngr (int only_daemon) if (log_get_fd () != -1) no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ()); no_close_list[i++] = assuan_fd_from_posix_fd (es_fileno (es_stderr)); - no_close_list[i] = -1; + no_close_list[i] = ASSUAN_INVALID_FD; /* Connect to the agent and perform initial handshaking. */ rc = assuan_pipe_connect (ctx, opt.dirmngr_program, argv, diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index 9f3e2ee..0cbdc7b 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -510,6 +510,10 @@ DWORD WINAPI w32_service_control (DWORD control, DWORD event_type, LPVOID event_data, LPVOID context) { + (void)event_type; + (void)event_data; + (void)context; + /* event_type and event_data are not used here. */ switch (control) { @@ -1016,6 +1020,9 @@ main (int argc, char **argv) existing scripts which might use this to detect a successful start of the dirmngr. */ #ifdef HAVE_W32_SYSTEM + (void)csh_style; + (void)nodetach; + pid = getpid (); es_printf ("set %s=%s;%lu;1\n", DIRMNGR_INFO_NAME, socket_name, (ulong) pid); @@ -1275,6 +1282,12 @@ main (int argc, char **argv) #ifdef USE_W32_SERVICE +static void WINAPI +call_real_main (DWORD argc, LPSTR *argv) +{ + real_main (argc, argv); +} + int main (int argc, char *argv[]) { @@ -1295,8 +1308,7 @@ main (int argc, char *argv[]) { SERVICE_TABLE_ENTRY DispatchTable [] = { - /* Ignore warning. */ - { "DirMngr", &real_main }, + { "DirMngr", &call_real_main }, { NULL, NULL } }; @@ -1609,12 +1621,12 @@ dirmngr_sighup_action (void) /* The signal handler. */ +#ifndef HAVE_W32_SYSTEM static void handle_signal (int signo) { switch (signo) { -#ifndef HAVE_W32_SYSTEM case SIGHUP: dirmngr_sighup_action (); break; @@ -1649,11 +1661,12 @@ handle_signal (int signo) cleanup (); dirmngr_exit (0); break; -#endif + default: log_info (_("signal %d received - no action defined\n"), signo); } } +#endif /*!HAVE_W32_SYSTEM*/ /* This is the worker for the ticker. It is called every few seconds @@ -1739,7 +1752,9 @@ static void handle_connections (assuan_fd_t listen_fd) { npth_attr_t tattr; +#ifndef HAVE_W32_SYSTEM int signo; +#endif struct sockaddr_un paddr; socklen_t plen = sizeof( paddr ); gnupg_fd_t fd; diff --git a/dirmngr/ldap-wrapper-ce.c b/dirmngr/ldap-wrapper-ce.c index 9af70af..ce63ea6 100644 --- a/dirmngr/ldap-wrapper-ce.c +++ b/dirmngr/ldap-wrapper-ce.c @@ -279,8 +279,6 @@ outstream_reader_cb (void *cb_value, char *buffer, size_t count, size_t *r_nread) { struct outstream_cookie_s *cookie = cb_value; - char *dst; - const char *src; size_t nread = 0; int was_full = 0; @@ -288,7 +286,6 @@ outstream_reader_cb (void *cb_value, char *buffer, size_t count, return gpg_error (GPG_ERR_NOT_SUPPORTED); /* Rewind is not supported. */ *r_nread = 0; - dst = buffer; while (BUFFER_EMPTY(cookie)) { @@ -302,7 +299,6 @@ outstream_reader_cb (void *cb_value, char *buffer, size_t count, if (BUFFER_FULL(cookie)) was_full = 1; - src = cookie->buffer + cookie->buffer_pos; nread = buffer_get_data (cookie, buffer, count); if (was_full) diff --git a/g10/tdbio.c b/g10/tdbio.c index db7a67c..2b9d4ff 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -38,7 +38,7 @@ #include "trustdb.h" #include "tdbio.h" -#if defined(HAVE_DOSISH_SYSTEM) +#if defined(HAVE_DOSISH_SYSTEM) && !defined(ftruncate) #define ftruncate chsize #endif commit 35266076e3452590931e58f188815859dff6de3c Author: Werner Koch Date: Fri Mar 7 09:46:44 2014 +0100 dirmngr: Simplify strtok macro. * dirmngr/ldap-url.c (ldap_utf8_strtok): Remove unused r3d arg. (ldap_str2charray): Remove lasts. -- I have no clue why an utf8 version was planned to be used. Do the LDAP folks really assume that eventually non-ascii delimiters might be used? Simplified it to silence the warning about an used helper var. diff --git a/dirmngr/ldap-url.c b/dirmngr/ldap-url.c index e5a7d94..8308514 100644 --- a/dirmngr/ldap-url.c +++ b/dirmngr/ldap-url.c @@ -91,7 +91,7 @@ software is provided `'as is'' without express or implied warranty. */ #define LDAP_MALLOC malloc #define LDAP_REALLOC realloc #define ldap_utf8_strchr strchr -#define ldap_utf8_strtok(n,d,s) strtok (n,d) +#define ldap_utf8_strtok(n,d) strtok (n,d) #define Debug(a,b,c,d,e) void ldap_pvt_hex_unescape( char *s ); @@ -267,7 +267,6 @@ ldap_str2charray( const char *str_in, const char *brkstr ) { char **res; char *str, *s; - char *lasts; int i; /* protect the input string from strtok */ @@ -292,9 +291,9 @@ ldap_str2charray( const char *str_in, const char *brkstr ) i = 0; - for ( s = ldap_utf8_strtok( str, brkstr, &lasts ); + for ( s = ldap_utf8_strtok( str, brkstr); s != NULL; - s = ldap_utf8_strtok( NULL, brkstr, &lasts ) ) + s = ldap_utf8_strtok( NULL, brkstr) ) { res[i] = LDAP_STRDUP( s ); commit 72133b54de89e593d8193b106e9369cf90d2e1c0 Author: Werner Koch Date: Fri Mar 7 09:46:44 2014 +0100 Use attribute __gnu_printf__ also in estream header files. * common/estream-printf.h: Use attribute gnu_printf. * common/estream.h: Ditto. diff --git a/common/estream-printf.h b/common/estream-printf.h index 138ed37..3c2253d 100644 --- a/common/estream-printf.h +++ b/common/estream-printf.h @@ -99,11 +99,15 @@ #endif /*_ESTREAM_EXT_SYM_PREFIX*/ #ifndef _ESTREAM_GCC_A_PRINTF -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) -# define _ESTREAM_GCC_A_PRINTF( f, a ) __attribute__ ((format (printf,f,a))) -#else -# define _ESTREAM_GCC_A_PRINTF( f, a ) -#endif +# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4 ) +# define _ESTREAM_GCC_A_PRINTF( f, a ) \ + __attribute__ ((format (__gnu_printf__,f,a))) +# elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) +# define _ESTREAM_GCC_A_PRINTF( f, a ) \ + __attribute__ ((format (printf,f,a))) +# else +# define _ESTREAM_GCC_A_PRINTF( f, a ) +# endif #endif /*_ESTREAM_GCC_A_PRINTF*/ diff --git a/common/estream.h b/common/estream.h index e3c28fe..e3e9fc8 100644 --- a/common/estream.h +++ b/common/estream.h @@ -241,11 +241,15 @@ typedef struct #ifndef _ESTREAM_GCC_A_PRINTF -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) -# define _ESTREAM_GCC_A_PRINTF( f, a ) __attribute__ ((format (printf,f,a))) -#else -# define _ESTREAM_GCC_A_PRINTF( f, a ) -#endif +# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4 ) +# define _ESTREAM_GCC_A_PRINTF( f, a ) \ + __attribute__ ((format (__gnu_printf__,f,a))) +# elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) +# define _ESTREAM_GCC_A_PRINTF( f, a ) \ + __attribute__ ((format (printf,f,a))) +# else +# define _ESTREAM_GCC_A_PRINTF( f, a ) +# endif #endif /*_ESTREAM_GCC_A_PRINTF*/ ----------------------------------------------------------------------- Summary of changes: common/estream-printf.h | 14 +++++++++----- common/estream.h | 14 +++++++++----- dirmngr/cdblib.c | 9 +++++---- dirmngr/dirmngr-client.c | 4 ++-- dirmngr/dirmngr.c | 23 +++++++++++++++++++---- dirmngr/dirmngr_ldap.c | 23 +++++++++++++++-------- dirmngr/ldap-url.c | 7 +++---- dirmngr/ldap-wrapper-ce.c | 4 ---- g10/tdbio.c | 2 +- 9 files changed, 63 insertions(+), 37 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Mon Mar 10 11:15:59 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Mon, 10 Mar 2014 11:15:59 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-342-gb278043 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via b278043a8f38e2706ccf617d2ac5661b33791d6b (commit) from feda379595e06583bc5b3610dec74890de29cb8e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b278043a8f38e2706ccf617d2ac5661b33791d6b Author: Werner Koch Date: Fri Mar 7 09:46:44 2014 +0100 Do not require libiconv for Android. * configure.ac (require_iconv): New. Set to false for android. (AM_ICONV): Run only if required. diff --git a/configure.ac b/configure.ac index dc4d1ae..6cb7e11 100644 --- a/configure.ac +++ b/configure.ac @@ -639,6 +639,7 @@ AC_ARG_VAR(CC_FOR_BUILD,[build system C compiler]) try_gettext=yes +require_iconv=yes have_dosish_system=no have_w32_system=no have_w32ce_system=no @@ -716,6 +717,9 @@ case "${host}" in ;; *-linux-androideabi) have_android_system=yes + # Android is fully utf-8 and we do not want to use iconv to + # keeps things simple + require_iconv=no run_tests=no ;; *) @@ -1165,8 +1169,14 @@ AC_DEFINE_UNQUOTED(PRINTABLE_OS_NAME, "$PRINTABLE_OS_NAME", # # Checking for iconv # -AM_ICONV - +if test "$require_iconv" = yes; then + AM_ICONV +else + LIBICONV= + LTLIBICONV= + AC_SUBST(LIBICONV) + AC_SUBST(LTLIBICONV) +fi # @@ -1786,7 +1796,8 @@ if test "$have_npth" = "no"; then ***]]) fi -if test "$am_func_iconv" != yes; then +if test "$require_iconv" = yes; then + if test "$am_func_iconv" != yes; then die=yes AC_MSG_NOTICE([[ *** @@ -1795,6 +1806,7 @@ if test "$am_func_iconv" != yes; then *** available at: *** http://ftp.gnu.org/gnu/libiconv/ ***]]) + fi fi if test "$die" = "yes"; then ----------------------------------------------------------------------- Summary of changes: configure.ac | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Mon Mar 10 16:10:43 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Mon, 10 Mar 2014 16:10:43 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-345-g57d26f3 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 57d26f39afb3c75e24a8d240d7af32b9d2b9775a (commit) via 9ab9f414fb919f0bc87c301c3e36180715d0aa4e (commit) via 8e9b1aa563040e272840a2e5df73971a1f03401d (commit) from b278043a8f38e2706ccf617d2ac5661b33791d6b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 57d26f39afb3c75e24a8d240d7af32b9d2b9775a Author: Werner Koch Date: Fri Mar 7 09:46:44 2014 +0100 Backport useful code from fixes for bug 1447. * configure.ac: Cehck for inet_ntop. * m4/libcurl.m4: Provide a #define for the version of the curl library. -- We do not have keyserver helpers anymore but this fixes may come handy eventually. diff --git a/configure.ac b/configure.ac index 6cb7e11..4b12f01 100644 --- a/configure.ac +++ b/configure.ac @@ -1303,7 +1303,7 @@ AC_FUNC_VPRINTF AC_FUNC_FORK AC_CHECK_FUNCS([strerror strlwr tcgetattr mmap canonicalize_file_name]) AC_CHECK_FUNCS([strcasecmp strncasecmp ctermid times gmtime_r strtoull]) -AC_CHECK_FUNCS([unsetenv fcntl ftruncate canonicalize_file_name]) +AC_CHECK_FUNCS([unsetenv fcntl ftruncate inet_ntop canonicalize_file_name]) AC_CHECK_FUNCS([gettimeofday getrusage getrlimit setrlimit clock_gettime]) AC_CHECK_FUNCS([atexit raise getpagesize strftime nl_langinfo setlocale]) AC_CHECK_FUNCS([waitpid wait4 sigaction sigprocmask pipe getaddrinfo]) diff --git a/m4/libcurl.m4 b/m4/libcurl.m4 index f6a631b..49caecc 100644 --- a/m4/libcurl.m4 +++ b/m4/libcurl.m4 @@ -65,6 +65,10 @@ AC_DEFUN([LIBCURL_CHECK_CONFIG], AC_PROG_AWK _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'" + # More recent versions of curl-config have a direct --vernum + # option, but we'd like this code to work with older versions as + # well, so just convert --version. + _libcurl_vernum_parse="eval $AWK '{printf \"0x%06X\",\$NF}'" _libcurl_try_link=yes @@ -188,6 +192,11 @@ x=CURLOPT_VERBOSE; AC_SUBST(LIBCURL_CPPFLAGS) AC_SUBST(LIBCURL) + _libcurl_vernum=`echo $_libcurl_version | $_libcurl_vernum_parse` + + AC_DEFINE_UNQUOTED(LIBCURL_VERNUM, $_libcurl_vernum, + [The version of the libcurl library in packed hex form]) + for _libcurl_feature in $_libcurl_features ; do AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1]) eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes @@ -228,6 +237,7 @@ x=CURLOPT_VERBOSE; unset _libcurl_protocol unset _libcurl_protocols unset _libcurl_version + unset _libcurl_vernum unset _libcurl_ldflags fi commit 9ab9f414fb919f0bc87c301c3e36180715d0aa4e Author: Werner Koch Date: Fri Mar 7 09:46:44 2014 +0100 scd: acquire lock in new_reader_slot. * scd/apdu.c (new_reader_slot): Acquire lock. (open_ct_reader, open_pcsc_reader_direct, open_pcsc_reader_wrapped) (open_ccid_reader, open_rapdu_reader): Release lock. (lock_slot, trylock_slot, unlock_slot): Move more to the top. -- Fixes a test case of: No libpcsclite1 installed. Run gpg-agent Run command "gpg-connect-agent learn /bye" with no card/token Sometimes it fails: ERR 100663356 Not supported While it should be always: ERR 100663404 Card error (cherry picked from commit 4f557cb9c2ebe274d6aacc60a09cd919055d01ed) Resolved conflicts: scd/apdu.c: pth/npth changes. Move lock helpers to the top. Take care of removed pcsc_no_service. diff --git a/scd/apdu.c b/scd/apdu.c index fc37fcf..c7d4735 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -373,9 +373,56 @@ static int pcsc_pinpad_modify (int slot, int class, int ins, int p0, int p1, Helper */ +static int +lock_slot (int slot) +{ +#ifdef USE_NPTH + int err; + + err = npth_mutex_lock (&reader_table[slot].lock); + if (err) + { + log_error ("failed to acquire apdu lock: %s\n", strerror (err)); + return SW_HOST_LOCKING_FAILED; + } +#endif /*USE_NPTH*/ + return 0; +} + +static int +trylock_slot (int slot) +{ +#ifdef USE_NPTH + int err; + + err = npth_mutex_trylock (&reader_table[slot].lock); + if (err == EBUSY) + return SW_HOST_BUSY; + else if (err) + { + log_error ("failed to acquire apdu lock: %s\n", strerror (err)); + return SW_HOST_LOCKING_FAILED; + } +#endif /*USE_NPTH*/ + return 0; +} + +static void +unlock_slot (int slot) +{ +#ifdef USE_NPTH + int err; + + err = npth_mutex_unlock (&reader_table[slot].lock); + if (err) + log_error ("failed to release apdu lock: %s\n", strerror (errno)); +#endif /*USE_NPTH*/ +} + /* Find an unused reader slot for PORTSTR and put it into the reader - table. Return -1 on error or the index into the reader table. */ + table. Return -1 on error or the index into the reader table. + Acquire slot's lock on successful return. Caller needs to unlock it. */ static int new_reader_slot (void) { @@ -404,6 +451,11 @@ new_reader_slot (void) reader_table[reader].lock_initialized = 1; } #endif /*USE_NPTH*/ + if (lock_slot (reader)) + { + log_error ("error locking mutex: %s\n", strerror (errno)); + return -1; + } reader_table[reader].connect_card = NULL; reader_table[reader].disconnect_card = NULL; reader_table[reader].close_reader = NULL; @@ -692,6 +744,7 @@ open_ct_reader (int port) log_error ("apdu_open_ct_reader failed on port %d: %s\n", port, ct_error_string (rc)); reader_table[reader].used = 0; + unlock_slot (reader); return -1; } @@ -713,6 +766,7 @@ open_ct_reader (int port) reader_table[reader].pinpad_modify = NULL; dump_reader_status (reader); + unlock_slot (reader); return reader; } @@ -1871,6 +1925,7 @@ open_pcsc_reader_direct (const char *portstr) log_error ("pcsc_establish_context failed: %s (0x%lx)\n", pcsc_error_string (err), err); reader_table[slot].used = 0; + unlock_slot (slot); return -1; } @@ -1884,6 +1939,7 @@ open_pcsc_reader_direct (const char *portstr) log_error ("error allocating memory for reader list\n"); pcsc_release_context (reader_table[slot].pcsc.context); reader_table[slot].used = 0; + unlock_slot (slot); return -1 /*SW_HOST_OUT_OF_CORE*/; } err = pcsc_list_readers (reader_table[slot].pcsc.context, @@ -1896,6 +1952,7 @@ open_pcsc_reader_direct (const char *portstr) pcsc_release_context (reader_table[slot].pcsc.context); reader_table[slot].used = 0; xfree (list); + unlock_slot (slot); return -1; } @@ -1921,6 +1978,7 @@ open_pcsc_reader_direct (const char *portstr) log_error ("error allocating memory for reader name\n"); pcsc_release_context (reader_table[slot].pcsc.context); reader_table[slot].used = 0; + unlock_slot (slot); return -1; } strcpy (reader_table[slot].rdrname, portstr? portstr : list); @@ -1940,6 +1998,7 @@ open_pcsc_reader_direct (const char *portstr) reader_table[slot].dump_status_reader = dump_pcsc_reader_status; dump_reader_status (slot); + unlock_slot (slot); return slot; } #endif /*!NEED_PCSC_WRAPPER */ @@ -1986,6 +2045,7 @@ open_pcsc_reader_wrapped (const char *portstr) { log_error ("error creating a pipe: %s\n", strerror (errno)); slotp->used = 0; + unlock_slot (slot); return -1; } if (pipe (wp) == -1) @@ -1994,6 +2054,7 @@ open_pcsc_reader_wrapped (const char *portstr) close (rp[0]); close (rp[1]); slotp->used = 0; + unlock_slot (slot); return -1; } @@ -2006,6 +2067,7 @@ open_pcsc_reader_wrapped (const char *portstr) close (wp[0]); close (wp[1]); slotp->used = 0; + unlock_slot (slot); return -1; } slotp->pcsc.pid = pid; @@ -2142,6 +2204,7 @@ open_pcsc_reader_wrapped (const char *portstr) pcsc_get_status (slot, &dummy_status); dump_reader_status (slot); + unlock_slot (slot); return slot; command_failed: @@ -2153,6 +2216,7 @@ open_pcsc_reader_wrapped (const char *portstr) kill (slotp->pcsc.pid, SIGTERM); slotp->pcsc.pid = (pid_t)(-1); slotp->used = 0; + unlock_slot (slot); /* There is no way to return SW. */ return -1; @@ -2541,6 +2605,7 @@ open_ccid_reader (const char *portstr) if (err) { slotp->used = 0; + unlock_slot (slot); return -1; } @@ -2575,6 +2640,7 @@ open_ccid_reader (const char *portstr) reader_table[slot].is_t0 = 0; dump_reader_status (slot); + unlock_slot (slot); return slot; } @@ -2813,6 +2879,7 @@ open_rapdu_reader (int portno, if (!slotp->rapdu.handle) { slotp->used = 0; + unlock_slot (slot); return -1; } @@ -2867,12 +2934,14 @@ open_rapdu_reader (int portno, dump_reader_status (slot); rapdu_msg_release (msg); + unlock_slot (slot); return slot; failure: rapdu_msg_release (msg); rapdu_release (slotp->rapdu.handle); slotp->used = 0; + unlock_slot (slot); return -1; } @@ -2885,53 +2954,6 @@ open_rapdu_reader (int portno, */ -static int -lock_slot (int slot) -{ -#ifdef USE_NPTH - int err; - - err = npth_mutex_lock (&reader_table[slot].lock); - if (err) - { - log_error ("failed to acquire apdu lock: %s\n", strerror (err)); - return SW_HOST_LOCKING_FAILED; - } -#endif /*USE_NPTH*/ - return 0; -} - -static int -trylock_slot (int slot) -{ -#ifdef USE_NPTH - int err; - - err = npth_mutex_trylock (&reader_table[slot].lock); - if (err == EBUSY) - return SW_HOST_BUSY; - else if (err) - { - log_error ("failed to acquire apdu lock: %s\n", strerror (err)); - return SW_HOST_LOCKING_FAILED; - } -#endif /*USE_NPTH*/ - return 0; -} - -static void -unlock_slot (int slot) -{ -#ifdef USE_NPTH - int err; - - err = npth_mutex_unlock (&reader_table[slot].lock); - if (err) - log_error ("failed to release apdu lock: %s\n", strerror (errno)); -#endif /*USE_NPTH*/ -} - - /* Open the reader and return an internal slot number or -1 on error. If PORTSTR is NULL we default to a suitable port (for ctAPI: the first USB reader. For PC/SC the first listed reader). */ commit 8e9b1aa563040e272840a2e5df73971a1f03401d Author: Werner Koch Date: Fri Nov 16 10:35:33 2012 +0100 Comment fixes. -- Reported-by: Daniel Kahn Gillmor (cherry picked from commit 7db5c81e3a40b60e146f29c6744a33fd1b88c090) diff --git a/g10/sign.c b/g10/sign.c index f5f0f95..d9f2dd3 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -421,10 +421,10 @@ match_dsa_hash (unsigned int qbytes) /* First try --digest-algo. If that isn't set, see if the recipient has a preferred algorithm (which is also filtered through - --preferred-digest-prefs). If we're making a signature without a + --personal-digest-prefs). If we're making a signature without a particular recipient (i.e. signing, rather than signing+encrypting) - then take the first algorithm in --preferred-digest-prefs that is - usable for the pubkey algorithm. If --preferred-digest-prefs isn't + then take the first algorithm in --personal-digest-prefs that is + usable for the pubkey algorithm. If --personal-digest-prefs isn't set, then take the OpenPGP default (i.e. SHA-1). Note that Ed25519+EdDSA takes an input of arbitrary length and thus ----------------------------------------------------------------------- Summary of changes: configure.ac | 2 +- g10/sign.c | 6 +-- m4/libcurl.m4 | 10 +++++ scd/apdu.c | 118 ++++++++++++++++++++++++++++++++++----------------------- 4 files changed, 84 insertions(+), 52 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Tue Mar 11 08:02:58 2014 From: cvs at cvs.gnupg.org (by NIIBE Yutaka) Date: Tue, 11 Mar 2014 08:02:58 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-346-gac5a1a3 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via ac5a1a3ccb7c3e6393bc83d73b545dec9b70e7d1 (commit) from 57d26f39afb3c75e24a8d240d7af32b9d2b9775a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit ac5a1a3ccb7c3e6393bc83d73b545dec9b70e7d1 Author: NIIBE Yutaka Date: Tue Mar 4 11:54:59 2014 +0900 agent: API change of agent_key_from_file. * agent/findkey.c (agent_key_from_file): Always return S-expression. * agent/command.c (cmd_passwd): Distinguish by SHADOW_INFO. (cmd_export_key): Likewise. Free SHADOW_INFO. (cmd_keytocard): Likewise. Release S_SKEY. * agent/pkdecrypt.c (agent_pkdecrypt): Likewise. * agent/pksign.c (agent_pksign_do): Likewise. Use the S-expression to know the key type. Signed-off-by: NIIBE Yutaka diff --git a/agent/command.c b/agent/command.c index 4fa40d9..d1e53cd 100644 --- a/agent/command.c +++ b/agent/command.c @@ -1667,7 +1667,7 @@ cmd_passwd (assuan_context_t ctx, char *line) &s_skey, &passphrase); if (err) ; - else if (!s_skey) + else if (shadow_info) { log_error ("changing a smartcard PIN is not yet supported\n"); err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); @@ -2126,6 +2126,7 @@ cmd_export_key (assuan_context_t ctx, char *line) int openpgp; char *cache_nonce; char *passphrase = NULL; + unsigned char *shadow_info = NULL; openpgp = has_option (line, "--openpgp"); cache_nonce = option_value (line, "--cache-nonce"); @@ -2163,15 +2164,13 @@ cmd_export_key (assuan_context_t ctx, char *line) /* Get the key from the file. With the openpgp flag we also ask for the passphrase so that we can use it to re-encrypt it. */ err = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip, - NULL, CACHE_MODE_IGNORE, NULL, &s_skey, + &shadow_info, CACHE_MODE_IGNORE, NULL, &s_skey, openpgp ? &passphrase : NULL); if (err) goto leave; - if (!s_skey) + if (shadow_info) { - /* Key is on a smartcard. Actually we should not see this here - because we do not pass a shadow_info variable to the above - function, thus it will return this error directly. */ + /* Key is on a smartcard. */ err = gpg_error (GPG_ERR_UNUSABLE_SECKEY); goto leave; } @@ -2241,6 +2240,7 @@ cmd_export_key (assuan_context_t ctx, char *line) gcry_sexp_release (s_skey); xfree (ctrl->server_local->keydesc); ctrl->server_local->keydesc = NULL; + xfree (shadow_info); return leave_cmd (ctx, err); } @@ -2260,7 +2260,7 @@ cmd_keytocard (assuan_context_t ctx, char *line) unsigned char *keydata; size_t keydatalen, timestamplen; const char *serialno, *timestamp_str, *id; - unsigned char *shadow_info; + unsigned char *shadow_info = NULL; unsigned char *shdkey; time_t timestamp; @@ -2305,12 +2305,20 @@ cmd_keytocard (assuan_context_t ctx, char *line) return gpg_error (GPG_ERR_INV_VALUE); err = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip, - NULL, CACHE_MODE_IGNORE, NULL, &s_skey, NULL); + &shadow_info, CACHE_MODE_IGNORE, NULL, + &s_skey, NULL); if (err) - return err; - if (!s_skey) - /* Key is on a smartcard already. */ - return gpg_error (GPG_ERR_UNUSABLE_SECKEY); + { + xfree (shadow_info); + return err; + } + if (shadow_info) + { + /* Key is on a smartcard already. */ + xfree (shadow_info); + gcry_sexp_release (s_skey); + return gpg_error (GPG_ERR_UNUSABLE_SECKEY); + } keydatalen = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0); keydata = xtrymalloc_secure (keydatalen + 30); diff --git a/agent/findkey.c b/agent/findkey.c index 6464b02..7b24c55 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -537,9 +537,9 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result) /* Return the secret key as an S-Exp in RESULT after locating it using - the GRIP. Stores NULL at RESULT if the operation shall be diverted - to a token; in this case an allocated S-expression with the - shadow_info part from the file is stored at SHADOW_INFO. + the GRIP. If the operation shall be diverted to a token, an + allocated S-expression with the shadow_info part from the file is + stored at SHADOW_INFO; if not NULL will be stored at SHADOW_INFO. CACHE_MODE defines now the cache shall be used. DESC_TEXT may be set to present a custom description for the pinentry. LOOKUP_TTL is an optional function to convey a TTL to the cache manager; we do @@ -562,7 +562,6 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, unsigned char *buf; size_t len, buflen, erroff; gcry_sexp_t s_skey; - int got_shadow_info = 0; *result = NULL; if (shadow_info) @@ -638,7 +637,6 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, { memcpy (*shadow_info, s, n); rc = 0; - got_shadow_info = 1; } } if (rc) @@ -654,7 +652,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, } gcry_sexp_release (s_skey); s_skey = NULL; - if (rc || got_shadow_info) + if (rc) { xfree (buf); if (r_passphrase) diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c index 9924d6d..14aa78f 100644 --- a/agent/pkdecrypt.c +++ b/agent/pkdecrypt.c @@ -79,7 +79,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, goto leave; } - if (!s_skey) + if (shadow_info) { /* divert operation to the smartcard */ if (!gcry_sexp_canon_len (ciphertext, ciphertextlen, NULL, NULL)) diff --git a/agent/pksign.c b/agent/pksign.c index 4d0a240..0886150 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -299,31 +299,20 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, goto leave; } - if (!s_skey) + if (shadow_info) { /* Divert operation to the smartcard */ - gcry_sexp_t s_pkey, l; - const char *name; size_t len; unsigned char *buf = NULL; + int key_type; int is_RSA = 0; int is_ECDSA = 0; - /* Check keytype by public key */ - rc = agent_public_key_from_file (ctrl, ctrl->keygrip, &s_pkey); - if (rc) - { - log_error ("failed to read the public key\n"); - goto leave; - } - l = gcry_sexp_cadr (s_pkey); - name = gcry_sexp_nth_data (l, 0, &len); - if (len == 3 && !memcmp (name, "rsa", 3)) + key_type = agent_is_dsa_key (s_skey); + if (key_type == 0) is_RSA = 1; - else if (len == 5 && !memcmp (name, "ecdsa", 5)) + else if (key_type == GCRY_PK_ECDSA) is_ECDSA = 1; - gcry_sexp_release (l); - gcry_sexp_release (s_pkey); rc = divert_pksign (ctrl, ctrl->digest.value, ----------------------------------------------------------------------- Summary of changes: agent/command.c | 32 ++++++++++++++++++++------------ agent/findkey.c | 10 ++++------ agent/pkdecrypt.c | 2 +- agent/pksign.c | 21 +++++---------------- 4 files changed, 30 insertions(+), 35 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Tue Mar 11 13:57:50 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Tue, 11 Mar 2014 13:57:50 +0100 Subject: [git] GPGME - branch, master, updated. gpgme-1.4.2-25-gdd9c8c5 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via dd9c8c56719db093b8daa23aa40b2be71bbd1526 (commit) via 75a6255935f450d56f3637cbb2b6c8161ace57ab (commit) from 40938feb3f3393b0cdc6ec61ca2e77ff0b82c69a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit dd9c8c56719db093b8daa23aa40b2be71bbd1526 Author: Werner Koch Date: Tue Mar 11 13:58:38 2014 +0100 Avoid pointer arithmetic on void pointer. * src/gpgme.c (gpgme_io_writen): Use new var buffer. -- Reported-by: Albert Chin diff --git a/src/gpgme.c b/src/gpgme.c index 4182c74..438fef2 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -691,8 +691,9 @@ gpgme_io_write (int fd, const void *buffer, size_t count) written or an error is return. Returns: 0 on success or -1 on error and the sets errno. */ int -gpgme_io_writen (int fd, const void *buffer, size_t count) +gpgme_io_writen (int fd, const void *buffer_arg, size_t count) { + const char *buffer = buffer_arg; int ret = 0; TRACE_BEG2 (DEBUG_GLOBAL, "gpgme_io_writen", fd, "buffer=%p, count=%u", buffer, count); commit 75a6255935f450d56f3637cbb2b6c8161ace57ab Author: Werner Koch Date: Tue Mar 11 13:54:21 2014 +0100 Change implementation return type to match the definition. * src/gpgme.c (gpgme_get_sub_protocol): Change return type to gpgme_protocol_t. -- Yet another enum/int mismatch. Reported-by: Albert Chin. diff --git a/src/gpgme.c b/src/gpgme.c index 9c297d8..4182c74 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -370,7 +370,7 @@ gpgme_set_sub_protocol (gpgme_ctx_t ctx, gpgme_protocol_t protocol) } -gpgme_error_t +gpgme_protocol_t gpgme_get_sub_protocol (gpgme_ctx_t ctx) { TRACE2 (DEBUG_CTX, "gpgme_get_sub_protocol", ctx, ----------------------------------------------------------------------- Summary of changes: src/gpgme.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Tue Mar 11 16:31:06 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Tue, 11 Mar 2014 16:31:06 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-350-ga3dee28 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via a3dee2889106fcab112c1c96b32e04d8154875e7 (commit) via 71b55c945542e695161ddbd783f87c5f534012a5 (commit) via 3c35b46a32ac7584f3807b611cde78b199c527d6 (commit) via f30d8b018871495327cbf711b73b04278a34f3e1 (commit) from ac5a1a3ccb7c3e6393bc83d73b545dec9b70e7d1 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a3dee2889106fcab112c1c96b32e04d8154875e7 Author: Werner Koch Date: Tue Mar 11 16:19:41 2014 +0100 dirmngr: Add command option to mark hosts as dead or alive. * dirmngr/server.c (cmd_killdirmngr): Factor some code out to ... (check_owner_permission): here. (cmd_keyserver): Add options --dead and --alive. * dirmngr/ks-engine-hkp.c (host_in_pool_p): New. (ks_hkp_mark_host): New. -- Also removed the warning that the widnows part has not yet been done. AFAICS, the current mingw supports the all used socket functions. diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 5d68cce..4075930 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -18,7 +18,6 @@ * along with this program; if not, see . */ -#warning fixme Windows part not yet done #include #include @@ -153,6 +152,19 @@ sort_hostpool (const void *xa, const void *xb) } +/* Return true if the host with the hosttable index TBLIDX is in POOL. */ +static int +host_in_pool_p (int *pool, int tblidx) +{ + int i, pidx; + + for (i=0; (pidx = pool[i]) != -1; i++) + if (pidx == tblidx && hosttable[pidx]) + return 1; + return 0; +} + + /* Select a random host. Consult TABLE which indices into the global hosttable. Returns index into TABLE or -1 if no host could be selected. */ @@ -374,6 +386,80 @@ mark_host_dead (const char *name) } +/* Mark a host in the hosttable as dead or - if ALIVE is true - as + alive. If the host NAME does not exist a warning status message is + printed. */ +gpg_error_t +ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive) +{ + gpg_error_t err = 0; + hostinfo_t hi, hi2; + int idx, idx2, idx3, n; + + if (!name || !*name || !strcmp (name, "localhost")) + return 0; + + idx = find_hostinfo (name); + if (idx == -1) + return gpg_error (GPG_ERR_NOT_FOUND); + + hi = hosttable[idx]; + if (alive && hi->dead) + { + hi->dead = 0; + err = ks_printf_help (ctrl, "marking '%s' as alive", name); + } + else if (!alive && !hi->dead) + { + hi->dead = 1; + err = ks_printf_help (ctrl, "marking '%s' as dead", name); + } + + /* If the host is a pool mark all member hosts. */ + if (!err && hi->pool) + { + for (idx2=0; !err && (n=hi->pool[idx2]) != -1; idx2++) + { + assert (n >= 0 && n < hosttable_size); + + if (!alive) + { + /* Do not mark a host from a pool dead if it is also a + member in another pool. */ + for (idx3=0; idx3 < hosttable_size; idx3++) + { + if (hosttable[idx3] && hosttable[idx3] + && hosttable[idx3]->pool + && idx3 != idx + && host_in_pool_p (hosttable[idx3]->pool, n)) + break; + } + if (idx3 < hosttable_size) + continue; /* Host is also a member of another pool. */ + } + + hi2 = hosttable[n]; + if (!hi2) + ; + else if (alive && hi2->dead) + { + hi2->dead = 0; + err = ks_printf_help (ctrl, "marking '%s' as alive", + hi2->name); + } + else if (!alive && !hi2->dead) + { + hi2->dead = 1; + err = ks_printf_help (ctrl, "marking '%s' as dead", + hi2->name); + } + } + } + + return err; +} + + /* Debug function to print the entire hosttable. */ gpg_error_t ks_hkp_print_hosttable (ctrl_t ctrl) diff --git a/dirmngr/ks-engine.h b/dirmngr/ks-engine.h index 01a295c..a2faa75 100644 --- a/dirmngr/ks-engine.h +++ b/dirmngr/ks-engine.h @@ -30,6 +30,7 @@ gpg_error_t ks_printf_help (ctrl_t ctrl, const char *format, /*-- ks-engine-hkp.c --*/ gpg_error_t ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri); +gpg_error_t ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive); gpg_error_t ks_hkp_print_hosttable (ctrl_t ctrl); gpg_error_t ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri); gpg_error_t ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, diff --git a/dirmngr/server.c b/dirmngr/server.c index d2682ea..fb619df 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -298,6 +298,32 @@ skip_options (char *line) } +/* Return an error if the assuan context does not belong to teh owner + of the process or to root. On error FAILTEXT is set as Assuan + error string. */ +static gpg_error_t +check_owner_permission (assuan_context_t ctx, const char *failtext) +{ +#ifdef HAVE_W32_SYSTEM + /* Under Windows the dirmngr is always run under the control of the + user. */ + (void)ctx; + (void)failtext; +#else + gpg_err_code_t ec; + assuan_peercred_t cred; + + ec = gpg_err_code (assuan_get_peercred (ctx, &cred)); + if (!ec && cred->uid && cred->uid != getuid ()) + ec = GPG_ERR_EPERM; + if (ec) + return set_error (ec, failtext); +#endif + return 0; +} + + + /* Common code for get_cert_local and get_issuer_cert_local. */ static ksba_cert_t do_get_cert_local (ctrl_t ctrl, const char *name, const char *command) @@ -1392,10 +1418,16 @@ cmd_validate (assuan_context_t ctx, char *line) static const char hlp_keyserver[] = - "KEYSERVER [--clear|--help] []\n" + "KEYSERVER [] [|]\n" + "Options are:\n" + " --help\n" + " --clear Remove all configured keyservers\n" + " --resolve Resolve HKP host names and rotate\n" + " --hosttable Print table of known hosts and pools\n" + " --dead Mark as dead\n" + " --alive Mark as alive\n" "\n" "If called without arguments list all configured keyserver URLs.\n" - "If called with option \"--clear\" remove all configured keyservers\n" "If called with an URI add this as keyserver. Note that keyservers\n" "are configured on a per-session base. A default keyserver may already be\n" "present, thus the \"--clear\" option must be used to get full control.\n" @@ -1408,6 +1440,7 @@ cmd_keyserver (assuan_context_t ctx, char *line) ctrl_t ctrl = assuan_get_pointer (ctx); gpg_error_t err = 0; int clear_flag, add_flag, help_flag, host_flag, resolve_flag; + int dead_flag, alive_flag; uri_item_t item = NULL; /* gcc 4.4.5 is not able to detect that it is always initialized. */ @@ -1415,6 +1448,8 @@ cmd_keyserver (assuan_context_t ctx, char *line) help_flag = has_option (line, "--help"); resolve_flag = has_option (line, "--resolve"); host_flag = has_option (line, "--hosttable"); + dead_flag = has_option (line, "--dead"); + alive_flag = has_option (line, "--alive"); line = skip_options (line); add_flag = !!*line; @@ -1431,13 +1466,37 @@ cmd_keyserver (assuan_context_t ctx, char *line) goto leave; } + if (alive_flag && dead_flag) + { + err = set_error (GPG_ERR_ASS_PARAMETER, "no support for zombies"); + goto leave; + } + if (dead_flag) + { + err = check_owner_permission (ctx, "no permission to use --dead"); + if (err) + goto leave; + } + if (alive_flag || dead_flag) + { + if (!*line) + { + err = set_error (GPG_ERR_ASS_PARAMETER, "name of host missing"); + goto leave; + } + + err = ks_hkp_mark_host (ctrl, line, alive_flag); + if (err) + goto leave; + } + if (host_flag) { err = ks_hkp_print_hosttable (ctrl); if (err) goto leave; } - if (resolve_flag || host_flag) + if (resolve_flag || host_flag || alive_flag || dead_flag) goto leave; if (add_flag) @@ -1746,30 +1805,28 @@ static gpg_error_t cmd_killdirmngr (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); + gpg_error_t err; (void)line; if (opt.system_daemon) { if (opt.system_service) - return set_error (GPG_ERR_NOT_SUPPORTED, - "can't do that whilst running as system service"); -#ifndef HAVE_W32_SYSTEM - { - gpg_err_code_t ec; - assuan_peercred_t cred; - - ec = gpg_err_code (assuan_get_peercred (ctx, &cred)); - if (!ec && cred->uid) - ec = GPG_ERR_EPERM; /* Only root may terminate. */ - if (ec) - return set_error (ec, "no permission to kill this process"); - } -#endif + err = set_error (GPG_ERR_NOT_SUPPORTED, + "can't do that whilst running as system service"); + else + err = check_owner_permission (ctx, + "no permission to kill this process"); } + else + err = 0; - ctrl->server_local->stopme = 1; - return gpg_error (GPG_ERR_EOF); + if (!err) + { + ctrl->server_local->stopme = 1; + err = gpg_error (GPG_ERR_EOF); + } + return err; } commit 71b55c945542e695161ddbd783f87c5f534012a5 Author: Werner Koch Date: Tue Mar 11 14:27:58 2014 +0100 dirmngr: Make Assuan output of keyblocks easier readable * dirmngr/server.c (data_line_cookie_write): Print shorter data lines in verbose mode. diff --git a/dirmngr/server.c b/dirmngr/server.c index 9a02441..d2682ea 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -141,14 +141,44 @@ leave_cmd (assuan_context_t ctx, gpg_error_t err) /* A write handler used by es_fopencookie to write assuan data lines. */ static ssize_t -data_line_cookie_write (void *cookie, const void *buffer, size_t size) +data_line_cookie_write (void *cookie, const void *buffer_arg, size_t size) { assuan_context_t ctx = cookie; + const char *buffer = buffer_arg; - if (assuan_send_data (ctx, buffer, size)) + if (opt.verbose && buffer && size) { - gpg_err_set_errno (EIO); - return -1; + /* Ease reading of output by sending a physical line at each LF. */ + const char *p; + size_t n, nbytes; + + nbytes = size; + do + { + p = memchr (buffer, '\n', nbytes); + n = p ? (p - buffer) + 1 : nbytes; + if (assuan_send_data (ctx, buffer, n)) + { + gpg_err_set_errno (EIO); + return -1; + } + buffer += n; + nbytes -= n; + if (nbytes && assuan_send_data (ctx, NULL, 0)) /* Flush line. */ + { + gpg_err_set_errno (EIO); + return -1; + } + } + while (nbytes); + } + else + { + if (assuan_send_data (ctx, buffer, size)) + { + gpg_err_set_errno (EIO); + return -1; + } } return size; commit 3c35b46a32ac7584f3807b611cde78b199c527d6 Author: Werner Koch Date: Tue Mar 11 14:26:39 2014 +0100 dirmngr: Fix HKP host selection code. * dirmngr/server.c (cmd_keyserver): Add option --resolve and change --print-hosttable to --hosttable. * dirmngr/ks-action.c (ks_printf_help): New. (ks_action_resolve): New. * dirmngr/ks-engine-hkp.c (select_random_host): Fix selection. (ks_hkp_print_hosttable): Print to assuan stream. (map_host): Remove debug code. Add arg FORCE_SELECT. Return numeric IP addr if it can't be resolved. (make_host_part): Add arg FORCE_SELECT; change callers to pass false. (ks_hkp_resolve): New. -- The new options for the keyserver command are useful for debugging. For example: $ tools/gpg-connect-agent -S /usr/local/var/run/gnupg/S.dirmngr \ 'keyserver hkp://keys.gnupg.net' \ 'keyserver http://http-keys.gnupg.net' \ 'keyserver --resolve --hosttable' /bye yields: OK OK S # http://astrath.net:80 S # http://2001:41d0:1:e673::1:11371 S # hosttable (idx, ipv4, ipv6, dead, name): S # 0 http-keys.gnupg.net S # . --> 10 11 12 1 5 8 7 4* 2 9 6 3 S # 1 4 37.250.168.245.bredband.tre.se S # 2 4 6 keys.exosphere.de S # 3 4 6 poseidon.muc.drweb-av.de S # 4 4 astrath.net S # 5 4 79.143.214.216 S # 6 4 openpgp.andrew.kvalhe.im S # 7 4 app.aaiedu.hr S # 8 4 6 alita.karotte.org S # 9 4 6 keyserver.bau5net.com S # 10 4 194.94.127.122 S # 11 6 2001:4d88:1ffc:477::7 S # 12 6 2a00:1280:8000:2:1:8:0:1 S # 13 keys.gnupg.net S # . --> 23 28* 30 17 22 8 7 27 25 14 21 20 19 29 [...] S # 14 4 hufu.ki.iif.hu S # 15 4 pks.ms.mff.cuni.cz S # 16 4 pgpkeys.co.uk S # 17 4 80-239-156-219.customer.teliacarrier.com S # 18 4 srv01.secure-u.de S # 19 4 mallos.xs4all.nl S # 20 4 kronecker.scientia.net S # 21 4 keyserver.ut.mephi.ru S # 22 4 89-68-150-88.dynamic.chello.pl S # 23 6 2001:1608:21:6:84:200:66:125 S # 24 6 sks.es.net S # 25 6 gstueve-1-pt.tunnel.tserv13.ash1.ipv6.he.net S # 26 6 sks.mrball.net S # 27 6 gozer.rediris.es S # 28 6 2001:41d0:1:e673::1 S # 29 6 oteiza.siccegge.de S # 30 6 2403:4200:401:10::13 S # 31 6 statler.serviz.fr OK diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c index 9ebf69b..dfeb862 100644 --- a/dirmngr/ks-action.c +++ b/dirmngr/ks-action.c @@ -1,5 +1,6 @@ /* ks-action.c - OpenPGP keyserver actions * Copyright (C) 2011 Free Software Foundation, Inc. + * Copyright (C) 2011, 2014 Werner Koch * * This file is part of GnuPG. * @@ -57,6 +58,25 @@ ks_print_help (ctrl_t ctrl, const char *text) } +/* Called by the engine's help functions to print the actual help. */ +gpg_error_t +ks_printf_help (ctrl_t ctrl, const char *format, ...) +{ + va_list arg_ptr; + gpg_error_t err; + char *buf; + + va_start (arg_ptr, format); + buf = es_vasprintf (format, arg_ptr); + err = buf? 0 : gpg_error_from_syserror (); + va_end (arg_ptr); + if (!err) + err = dirmngr_status_help (ctrl, buf); + es_free (buf); + return err; +} + + /* Run the help command for the engine responsible for URI. */ gpg_error_t ks_action_help (ctrl_t ctrl, const char *url) @@ -94,6 +114,32 @@ ks_action_help (ctrl_t ctrl, const char *url) } +/* Resolve all host names. This is useful for looking at the status + of configured keyservers. */ +gpg_error_t +ks_action_resolve (ctrl_t ctrl) +{ + gpg_error_t err = 0; + int any = 0; + uri_item_t uri; + + for (uri = ctrl->keyservers; !err && uri; uri = uri->next) + { + if (uri->parsed_uri->is_http) + { + any = 1; + err = ks_hkp_resolve (ctrl, uri->parsed_uri); + if (err) + break; + } + } + + if (!any) + err = gpg_error (GPG_ERR_NO_KEYSERVER); + return err; +} + + /* Search all configured keyservers for keys matching PATTERNS and write the result to the provided output stream. */ gpg_error_t @@ -193,7 +239,7 @@ ks_action_get (ctrl_t ctrl, strlist_t patterns, estream_t outfp) } -/* Retrive keys from URL and write the result to the provided output +/* Retrieve keys from URL and write the result to the provided output stream OUTFP. */ gpg_error_t ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp) diff --git a/dirmngr/ks-action.h b/dirmngr/ks-action.h index 3dca90f..5c8a5cd 100644 --- a/dirmngr/ks-action.h +++ b/dirmngr/ks-action.h @@ -21,6 +21,7 @@ #define DIRMNGR_KS_ACTION_H 1 gpg_error_t ks_action_help (ctrl_t ctrl, const char *url); +gpg_error_t ks_action_resolve (ctrl_t ctrl); gpg_error_t ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp); gpg_error_t ks_action_get (ctrl_t ctrl, strlist_t patterns, estream_t outfp); gpg_error_t ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp); diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 0c13185..5d68cce 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -1,5 +1,6 @@ /* ks-engine-hkp.c - HKP keyserver engine * Copyright (C) 2011, 2012 Free Software Foundation, Inc. + * Copyright (C) 2011, 2012, 2014 Werner Koch * * This file is part of GnuPG. * @@ -94,6 +95,7 @@ create_new_hostinfo (const char *name) hi->lastfail = (time_t)(-1); hi->v4 = 0; hi->v6 = 0; + hi->dead = 0; /* Add it to the hosttable. */ for (idx=0; idx < hosttable_size; idx++) @@ -161,8 +163,8 @@ select_random_host (int *table) size_t tblsize; int pidx, idx; - /* We create a new table so that we select only from currently alive - hosts. */ + /* We create a new table so that we randomly select only from + currently alive hosts. */ for (idx=0, tblsize=0; (pidx = table[idx]) != -1; idx++) if (hosttable[pidx] && !hosttable[pidx]->dead) tblsize++; @@ -179,7 +181,7 @@ select_random_host (int *table) if (tblsize == 1) /* Save a get_uint_nonce. */ pidx = tbl[0]; else - pidx = get_uint_nonce () % tblsize; + pidx = tbl[get_uint_nonce () % tblsize]; xfree (tbl); return pidx; @@ -190,9 +192,10 @@ select_random_host (int *table) allows us to manage round robin DNS names. We use our own strategy to choose one of the hosts. For example we skip those hosts which failed for some time and we stick to one host for a time - independent of DNS retry times. */ + independent of DNS retry times. If FORCE_RESELECT is true a new + host is always selected. */ static char * -map_host (const char *name) +map_host (const char *name, int force_reselect) { hostinfo_t hi; int idx; @@ -241,12 +244,13 @@ map_host (const char *name) if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) continue; - log_printhex ("getaddrinfo returned", ai->ai_addr,ai->ai_addrlen); if ((ec=getnameinfo (ai->ai_addr, ai->ai_addrlen, tmphost, sizeof tmphost, - NULL, 0, NI_NAMEREQD))) - log_info ("getnameinfo failed while checking '%s': %s\n", - name, gai_strerror (ec)); + NULL, 0, 0))) + { + log_info ("getnameinfo failed while checking '%s': %s\n", + name, gai_strerror (ec)); + } else if (refidx+1 >= reftblsize) { log_error ("getnameinfo returned for '%s': '%s'" @@ -266,7 +270,7 @@ map_host (const char *name) for (i=0; i < refidx; i++) if (reftbl[i] == tmpidx) - break; + break; if (!(i < refidx) && tmpidx != idx) reftbl[refidx++] = tmpidx; } @@ -319,8 +323,10 @@ map_host (const char *name) { /* If the currently selected host is now marked dead, force a re-selection . */ - if (hi->poolidx >= 0 && hi->poolidx < hosttable_size - && hosttable[hi->poolidx] && hosttable[hi->poolidx]->dead) + if (force_reselect) + hi->poolidx = -1; + else if (hi->poolidx >= 0 && hi->poolidx < hosttable_size + && hosttable[hi->poolidx] && hosttable[hi->poolidx]->dead) hi->poolidx = -1; /* Select a host if needed. */ @@ -369,33 +375,48 @@ mark_host_dead (const char *name) /* Debug function to print the entire hosttable. */ -void -ks_hkp_print_hosttable (void) +gpg_error_t +ks_hkp_print_hosttable (ctrl_t ctrl) { + gpg_error_t err; int idx, idx2; hostinfo_t hi; + membuf_t mb; + char *p; + + err = ks_print_help (ctrl, "hosttable (idx, ipv4, ipv6, dead, name):"); + if (err) + return err; for (idx=0; idx < hosttable_size; idx++) if ((hi=hosttable[idx])) { - log_info ("hosttable %3d %s %s %s %s\n", - idx, hi->v4? "4":" ", hi->v6? "6":" ", - hi->dead? "d":" ", hi->name); + err = ks_printf_help (ctrl, "%3d %s %s %s %s\n", + idx, hi->v4? "4":" ", hi->v6? "6":" ", + hi->dead? "d":" ", hi->name); + if (err) + return err; if (hi->pool) { - log_info (" -->"); + init_membuf (&mb, 256); + put_membuf_printf (&mb, " . -->"); for (idx2=0; hi->pool[idx2] != -1; idx2++) { - log_printf (" %d", hi->pool[idx2]); - if (hi->poolidx == idx2) - log_printf ("*"); + put_membuf_printf (&mb, " %d", hi->pool[idx2]); + if (hi->poolidx == hi->pool[idx2]) + put_membuf_printf (&mb, "*"); } - log_printf ("\n"); - /* for (idx2=0; hi->pool[idx2] != -1; idx2++) */ - /* log_info (" (%s)\n", */ - /* hosttable[hi->pool[idx2]]->name); */ + put_membuf( &mb, "", 1); + p = get_membuf (&mb, NULL); + if (!p) + return gpg_error_from_syserror (); + err = ks_print_help (ctrl, p); + xfree (p); + if (err) + return err; } } + return 0; } @@ -425,7 +446,8 @@ ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri) PORT. Returns an allocated string or NULL on failure and sets ERRNO. */ static char * -make_host_part (const char *scheme, const char *host, unsigned short port) +make_host_part (const char *scheme, const char *host, unsigned short port, + int force_reselect) { char portstr[10]; char *hostname; @@ -449,7 +471,7 @@ make_host_part (const char *scheme, const char *host, unsigned short port) /*fixme_do_srv_lookup ()*/ } - hostname = map_host (host); + hostname = map_host (host, force_reselect); if (!hostname) return NULL; @@ -459,6 +481,32 @@ make_host_part (const char *scheme, const char *host, unsigned short port) } +/* Resolve all known keyserver names and update the hosttable. This + is mainly useful for debugging because the resolving is anyway done + on demand. */ +gpg_error_t +ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri) +{ + gpg_error_t err; + char *hostport = NULL; + + hostport = make_host_part (uri->scheme, uri->host, uri->port, 1); + if (!hostport) + { + err = gpg_error_from_syserror (); + err = ks_printf_help (ctrl, "%s://%s:%hu: resolve failed: %s", + uri->scheme, uri->host, uri->port, + gpg_strerror (err)); + } + else + { + err = ks_printf_help (ctrl, "%s", hostport); + xfree (hostport); + } + return err; +} + + /* Send an HTTP request. On success returns an estream object at R_FP. HOSTPORTSTR is only used for diagnostics. If POST_CB is not NULL a post request is used and that callback is called to allow @@ -636,7 +684,6 @@ armor_data (char **r_string, const void *data, size_t datalen) } - /* Search the keyserver identified by URI for keys matching PATTERN. On success R_FP has an open stream to read the data. */ @@ -694,7 +741,7 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, { char *searchkey; - hostport = make_host_part (uri->scheme, uri->host, uri->port); + hostport = make_host_part (uri->scheme, uri->host, uri->port, 0); if (!hostport) { err = gpg_error_from_syserror (); @@ -725,7 +772,7 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, if (err) goto leave; - /* Start reading the response. */ + /* Peek at the response. */ { int c = es_getc (fp); if (c == -1) @@ -736,8 +783,8 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, } if (c == '<') { - /* The document begins with a '<', assume it's a HTML - response, which we don't support. */ + /* The document begins with a '<': Assume a HTML response, + which we don't support. */ err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING); goto leave; } @@ -800,7 +847,7 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) } /* Build the request string. */ - hostport = make_host_part (uri->scheme, uri->host, uri->port); + hostport = make_host_part (uri->scheme, uri->host, uri->port, 0); if (!hostport) { err = gpg_error_from_syserror (); @@ -892,7 +939,7 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen) armored = NULL; /* Build the request string. */ - hostport = make_host_part (uri->scheme, uri->host, uri->port); + hostport = make_host_part (uri->scheme, uri->host, uri->port, 0); if (!hostport) { err = gpg_error_from_syserror (); diff --git a/dirmngr/ks-engine.h b/dirmngr/ks-engine.h index cda31a7..01a295c 100644 --- a/dirmngr/ks-engine.h +++ b/dirmngr/ks-engine.h @@ -25,9 +25,12 @@ /*-- ks-action.c --*/ gpg_error_t ks_print_help (ctrl_t ctrl, const char *text); +gpg_error_t ks_printf_help (ctrl_t ctrl, const char *format, + ...) _ESTREAM_GCC_A_PRINTF(2,3); /*-- ks-engine-hkp.c --*/ -void ks_hkp_print_hosttable (void); +gpg_error_t ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri); +gpg_error_t ks_hkp_print_hosttable (ctrl_t ctrl); gpg_error_t ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri); gpg_error_t ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, estream_t *r_fp); diff --git a/dirmngr/server.c b/dirmngr/server.c index 6d7723a..9a02441 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -1,15 +1,16 @@ -/* dirmngr.c - LDAP access - * Copyright (C) 2002 Klar?lvdalens Datakonsult AB - * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2011 g10 Code GmbH +/* server.c - LDAP and Keyserver access server + * Copyright (C) 2002 Klar?lvdalens Datakonsult AB + * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2011 g10 Code GmbH + * Copyright (C) 2014 Werner Koch * - * This file is part of DirMngr. + * This file is part of GnuPG. * - * DirMngr is free software; you can redistribute it and/or modify + * 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 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * - * DirMngr is distributed in the hope that it will be useful, + * 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. @@ -120,6 +121,7 @@ release_ctrl_keyservers (ctrl_t ctrl) /* Helper to print a message while leaving a command. */ static gpg_error_t leave_cmd (assuan_context_t ctx, gpg_error_t err) + { if (err) { @@ -1374,14 +1376,15 @@ static gpg_error_t cmd_keyserver (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); - gpg_error_t err; - int clear_flag, add_flag, help_flag, host_flag; + gpg_error_t err = 0; + int clear_flag, add_flag, help_flag, host_flag, resolve_flag; uri_item_t item = NULL; /* gcc 4.4.5 is not able to detect that it is always initialized. */ clear_flag = has_option (line, "--clear"); help_flag = has_option (line, "--help"); - host_flag = has_option (line, "--print-hosttable"); + resolve_flag = has_option (line, "--resolve"); + host_flag = has_option (line, "--hosttable"); line = skip_options (line); add_flag = !!*line; @@ -1391,12 +1394,21 @@ cmd_keyserver (assuan_context_t ctx, char *line) goto leave; } + if (resolve_flag) + { + err = ks_action_resolve (ctrl); + if (err) + goto leave; + } + if (host_flag) { - ks_hkp_print_hosttable (); - err = 0; - goto leave; + err = ks_hkp_print_hosttable (ctrl); + if (err) + goto leave; } + if (resolve_flag || host_flag) + goto leave; if (add_flag) { commit f30d8b018871495327cbf711b73b04278a34f3e1 Author: Werner Koch Date: Tue Mar 11 09:24:16 2014 +0100 List readline support in configure summary * m4/readline.m4: Set gnupg_cv_have_readline. * configure.ac: Add readline support to summary output. -- Readline is an optional feature which is build if the readline development files are available on the build systems. Too often they are missing on a (new) build machine which at least makes debugging inconvenient. Backport useful code from fixes for bug 1447. * configure.ac: Cehck for inet_ntop. * m4/libcurl.m4: Provide a #define for the version of the curl library. -- We do not have keyserver helpers anymore but this fixes may come handy eventually. diff --git a/configure.ac b/configure.ac index 4b12f01..c20984a 100644 --- a/configure.ac +++ b/configure.ac @@ -1870,6 +1870,7 @@ echo " Use standard socket: $use_standard_socket Dirmngr auto start: $dirmngr_auto_start + Readline support: $gnupg_cv_have_readline " if test x"$use_regex" != xyes ; then echo " diff --git a/m4/readline.m4 b/m4/readline.m4 index 783f401..0c9619d 100644 --- a/m4/readline.m4 +++ b/m4/readline.m4 @@ -10,6 +10,7 @@ dnl dnl Defines HAVE_LIBREADLINE to 1 if a working readline setup is dnl found, and sets @LIBREADLINE@ to the necessary libraries. + AC_DEFUN([GNUPG_CHECK_READLINE], [ AC_ARG_WITH(readline, @@ -17,6 +18,7 @@ AC_DEFUN([GNUPG_CHECK_READLINE], [look for the readline library in DIR]), [_do_readline=$withval],[_do_readline=yes]) + gnupg_cv_have_readline=no if test "$_do_readline" != "no" ; then if test -d "$withval" ; then CPPFLAGS="${CPPFLAGS} -I$withval/include" @@ -51,6 +53,7 @@ rl_completion_matches(NULL,NULL); AC_DEFINE(HAVE_LIBREADLINE,1, [Define to 1 if you have a fully functional readline library.]) AC_SUBST(LIBREADLINE,$_combo) + gnupg_cv_have_readline=yes break fi done ----------------------------------------------------------------------- Summary of changes: configure.ac | 1 + dirmngr/ks-action.c | 48 ++++++++++- dirmngr/ks-action.h | 1 + dirmngr/ks-engine-hkp.c | 203 +++++++++++++++++++++++++++++++++++++++-------- dirmngr/ks-engine.h | 6 +- dirmngr/server.c | 169 +++++++++++++++++++++++++++++++-------- m4/readline.m4 | 3 + 7 files changed, 359 insertions(+), 72 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Tue Mar 11 18:01:32 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Tue, 11 Mar 2014 18:01:32 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-351-g0b2cca8 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 0b2cca807d5a4a3664145032271141da853e7bac (commit) from a3dee2889106fcab112c1c96b32e04d8154875e7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 0b2cca807d5a4a3664145032271141da853e7bac Author: Werner Koch Date: Tue Mar 11 18:02:29 2014 +0100 dirmngr: Put brackets around IP addresses in the hosttable. * dirmngr/ks-engine-hkp.c (EAI_OVERFLOW): Provide a substitute. (my_getnameinfo): New. (map_host): Use it. diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 4075930..13da3cb 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -40,6 +40,12 @@ #include "userids.h" #include "ks-engine.h" +/* Substitute a missing Mingw macro. */ +#ifndef EAI_OVERFLOW +# define EAI_OVERFLOW EAI_FAIL +#endif + + /* To match the behaviour of our old gpgkeys helper code we escape more characters than actually needed. */ #define EXTRA_ESCAPE_CHARS "@!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~" @@ -200,6 +206,35 @@ select_random_host (int *table) } +/* Simplified version of getnameinfo which also returns a numeric + hostname inside of brackets. The caller should provide a buffer + for TMPHOST which is 2 bytes larger than the the largest hostname. + returns 0 on success or an EAI error code. */ +static int +my_getnameinfo (const struct sockaddr *sa, socklen_t salen, + char *host, size_t hostlen) +{ + int ec; + + if (hostlen < 5) + return EAI_OVERFLOW; + + ec = getnameinfo (sa, salen, host, hostlen, NULL, 0, NI_NAMEREQD); + if (!ec && *host == '[') + ec = EAI_FAIL; /* A name may never start with a bracket. */ + else if (ec == EAI_NONAME) + { + *host = '['; + ec = getnameinfo (sa, salen, host + 1, hostlen - 2, + NULL, 0, NI_NUMERICHOST); + if (!ec) + strcat (host, "]"); + } + + return ec; +} + + /* Map the host name NAME to the actual to be used host name. This allows us to manage round robin DNS names. We use our own strategy to choose one of the hosts. For example we skip those hosts which @@ -256,9 +291,8 @@ map_host (const char *name, int force_reselect) if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) continue; - if ((ec=getnameinfo (ai->ai_addr, ai->ai_addrlen, - tmphost, sizeof tmphost, - NULL, 0, 0))) + if ((ec = my_getnameinfo (ai->ai_addr, ai->ai_addrlen, + tmphost, sizeof tmphost))) { log_info ("getnameinfo failed while checking '%s': %s\n", name, gai_strerror (ec)); ----------------------------------------------------------------------- Summary of changes: dirmngr/ks-engine-hkp.c | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Tue Mar 11 22:08:51 2014 From: cvs at cvs.gnupg.org (by Dmitry Eremin-Solenikov) Date: Tue, 11 Mar 2014 22:08:51 +0100 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.6.0-59-g5a8e150 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 5a8e1504bf8a2ffbc018be576dea77b685200444 (commit) from 2b5403c408dfbd71be24c7635f5fa0b61ab4c9bb (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 5a8e1504bf8a2ffbc018be576dea77b685200444 Author: Dmitry Eremin-Solenikov Date: Tue Mar 11 21:53:05 2014 +0400 Add MD2 message digest implementation * cipher/md2.c: New. * cipher/md.c (digest_list): add _gcry_digest_spec_md2. * tests/basic.c (check_digests): add MD2 test vectors. * configure.ac (default_digests): disable md2 by default. -- Signed-off-by: Dmitry Eremin-Solenikov Some minor indentation fixes by wk. diff --git a/cipher/md.c b/cipher/md.c index a332e03..461ad64 100644 --- a/cipher/md.c +++ b/cipher/md.c @@ -75,6 +75,9 @@ static gcry_md_spec_t *digest_list[] = #if USE_MD4 &_gcry_digest_spec_md4, #endif +#if USE_MD2 + &_gcry_digest_spec_md2, +#endif NULL }; diff --git a/cipher/md2.c b/cipher/md2.c new file mode 100644 index 0000000..97682e5 --- /dev/null +++ b/cipher/md2.c @@ -0,0 +1,182 @@ +/* md2.c - MD2 Message-Digest Algorithm + * Copyright (C) 2014 Dmitry Eremin-Solenikov + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include "g10lib.h" +#include "cipher.h" + +#include "bithelp.h" +#include "bufhelp.h" +#include "hash-common.h" + +typedef struct { + gcry_md_block_ctx_t bctx; + unsigned char C[16]; + unsigned char L; + unsigned char X[48]; +} MD2_CONTEXT; + +static const unsigned char S[] = + { + 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, + 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, + 0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, + 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, + 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, + 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, + 0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, + 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A, + 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, + 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, + 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, + 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, + 0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, + 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6, + 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, + 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, + 0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, + 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02, + 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, + 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, + 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, + 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, + 0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, + 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52, + 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, + 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, + 0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, + 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, + 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, + 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, + 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, + 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14 +}; + + +static void +permute (unsigned char *X, const unsigned char *buf) +{ + int i, j; + unsigned char t; + + memcpy (X+16, buf, 16); + for (i = 0; i < 16; i++) + X[32+i] = X[16+i] ^ X[i]; + t = 0; + for (i = 0; i < 18; i++) + { + for (j = 0; j < 48; j++) + { + t = X[j] ^ S[t]; + X[j] = t; + } + t += i; + } +} + + +static unsigned int +transform_blk (void *c, const unsigned char *data) +{ + MD2_CONTEXT *ctx = c; + int j; + + for (j = 0; j < 16; j++) + { + ctx->C[j] ^= S[data[j] ^ ctx->L]; + ctx->L = ctx->C[j]; + } + + permute(ctx->X, data); + + return /* burn stack */ 4 + 5 * sizeof(void*); +} + + +static unsigned int +transform ( void *c, const unsigned char *data, size_t nblks ) +{ + unsigned int burn; + + do + { + burn = transform_blk (c, data); + data += 64; + } + while (--nblks); + + return burn; +} + + +static void +md2_init (void *context, unsigned int flags) +{ + MD2_CONTEXT *ctx = context; + + (void)flags; + + memset (ctx, 0, sizeof(*ctx)); + ctx->bctx.blocksize = 16; + ctx->bctx.bwrite = transform; +} + + +static void +md2_final (void *context) +{ + MD2_CONTEXT *hd = context; + unsigned int burn; + + _gcry_md_block_write(hd, NULL, 0); /* flush */; + + /* pad */ + memset (hd->bctx.buf + hd->bctx.count, + 16 - hd->bctx.count, 16 - hd->bctx.count); + burn = transform_blk (hd, hd->bctx.buf); + permute (hd->X, hd->C); +} + +static byte * +md2_read (void *context) +{ + MD2_CONTEXT *hd = (MD2_CONTEXT *) context; + return hd->X; +} + +static byte asn[18] = /* Object ID is 1.2.840.113549.2.2 */ + { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,0x48, + 0x86, 0xf7, 0x0d, 0x02, 0x02, 0x05, 0x00, 0x04, 0x10 }; + +static gcry_md_oid_spec_t oid_spec_md2[] = + { + /* iso.member-body.us.rsadsi.digestAlgorithm.md2 */ + { "1.2.840.113549.2.2" }, + { NULL }, + }; + +gcry_md_spec_t _gcry_digest_spec_md2 = + { + GCRY_MD_MD2, {0, 0}, + "MD2", asn, DIM (asn), oid_spec_md2, 16, + md2_init, _gcry_md_block_write, md2_final, md2_read, + sizeof (MD2_CONTEXT) + }; diff --git a/configure.ac b/configure.ac index a447859..a0f75a5 100644 --- a/configure.ac +++ b/configure.ac @@ -194,7 +194,7 @@ available_pubkey_ciphers="dsa elgamal rsa ecc" enabled_pubkey_ciphers="" # Definitions for message digests. -available_digests="crc gostr3411-94 md4 md5 rmd160 sha1 sha256" +available_digests="crc gostr3411-94 md2 md4 md5 rmd160 sha1 sha256" available_digests_64="sha512 tiger whirlpool stribog" enabled_digests="" @@ -377,6 +377,8 @@ default_ciphers="$available_ciphers" default_pubkey_ciphers="$available_pubkey_ciphers" default_digests="$available_digests" default_kdfs="$available_kdfs" +# Blacklist MD2 by default +default_digests=`echo $default_digests | sed -e 's/md2//g'` # Substitutions to set generated files in a Emacs buffer to read-only. AC_SUBST(emacs_local_vars_begin, ['Local Variables:']) @@ -1845,6 +1847,12 @@ if test "$found" = "1" ; then AC_DEFINE(USE_GOST_R_3411_12, 1, [Defined if this module should be included]) fi +LIST_MEMBER(md2, $enabled_digests) +if test "$found" = "1" ; then + GCRYPT_DIGESTS="$GCRYPT_DIGESTS md2.lo" + AC_DEFINE(USE_MD2, 1, [Defined if this module should be included]) +fi + LIST_MEMBER(md4, $enabled_digests) if test "$found" = "1" ; then GCRYPT_DIGESTS="$GCRYPT_DIGESTS md4.lo" diff --git a/src/cipher.h b/src/cipher.h index 26ffddc..cd981b3 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -246,6 +246,7 @@ extern gcry_md_spec_t _gcry_digest_spec_crc24_rfc2440; extern gcry_md_spec_t _gcry_digest_spec_gost3411_94; extern gcry_md_spec_t _gcry_digest_spec_stribog_256; extern gcry_md_spec_t _gcry_digest_spec_stribog_512; +extern gcry_md_spec_t _gcry_digest_spec_md2; extern gcry_md_spec_t _gcry_digest_spec_md4; extern gcry_md_spec_t _gcry_digest_spec_md5; extern gcry_md_spec_t _gcry_digest_spec_rmd160; diff --git a/tests/basic.c b/tests/basic.c index e21e055..0eb0f77 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -3784,6 +3784,12 @@ check_digests (void) const char *expect; } algos[] = { + { GCRY_MD_MD2, "", + "\x83\x50\xe5\xa3\xe2\x4c\x15\x3d\xf2\x27\x5c\x9f\x80\x69\x27\x73" }, + { GCRY_MD_MD2, "a", + "\x32\xec\x01\xec\x4a\x6d\xac\x72\xc0\xab\x96\xfb\x34\xc0\xb5\xd1" }, + { GCRY_MD_MD2, "message digest", + "\xab\x4f\x49\x6b\xfb\x2a\x53\x0b\x21\x9f\xf3\x30\x31\xfe\x06\xb0" }, { GCRY_MD_MD4, "", "\x31\xD6\xCF\xE0\xD1\x6A\xE9\x31\xB7\x3C\x59\xD7\xE0\xC0\x89\xC0" }, { GCRY_MD_MD4, "a", ----------------------------------------------------------------------- Summary of changes: cipher/md.c | 3 + cipher/md2.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 10 +++- src/cipher.h | 1 + tests/basic.c | 6 ++ 5 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 cipher/md2.c hooks/post-receive -- The GNU crypto library http://git.gnupg.org From cvs at cvs.gnupg.org Wed Mar 12 09:25:21 2014 From: cvs at cvs.gnupg.org (by NIIBE Yutaka) Date: Wed, 12 Mar 2014 09:25:21 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-352-g781b941 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 781b94174310dceffa075719420b74b29fe41764 (commit) from 0b2cca807d5a4a3664145032271141da853e7bac (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 781b94174310dceffa075719420b74b29fe41764 Author: NIIBE Yutaka Date: Wed Mar 12 17:25:33 2014 +0900 scd: writekey support of ECC. * scd/app-openpgp.c (CURVE_SEC_P256K1, get_algo_byte): New. (store_fpr): Support ECC keys with varargs. (get_ecc_key_parameters, get_curve_name): Support secp256k1. (parse_ecc_curve): Likewise. (build_ecdsa_privkey_template, rsa_writekey, ecdsa_writekey): New. (ecdh_writekey): New. Not implemented yet. (do_writekey): Call rsa_writekey, ecdsa_writekey, or ecdh_writekey. (do_genkey): Follow the change of store_fpr. Signed-off-by: NIIBE Yutaka diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 3d7136f..da1bec9 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1,6 +1,6 @@ /* app-openpgp.c - The OpenPGP card application. * Copyright (C) 2003, 2004, 2005, 2007, 2008, - * 2009, 2013 Free Software Foundation, Inc. + * 2009, 2013, 2014 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -143,7 +144,9 @@ enum { CURVE_NIST_P256, CURVE_NIST_P384, - CURVE_NIST_P521 + CURVE_NIST_P521, + CURVE_SEC_P256K1, + CURVE_UNKOWN, }; @@ -735,24 +738,58 @@ parse_login_data (app_t app) xfree (relptr); } + +static unsigned char +get_algo_byte (key_type_t key_type) +{ + if (key_type == KEY_TYPE_ECDSA) + return 19; + else if (key_type == KEY_TYPE_ECDH) + return 18; + else + return 1; /* RSA */ +} + +#define MAX_ARGS_STORE_FPR 3 + /* Note, that FPR must be at least 20 bytes. */ static gpg_error_t store_fpr (app_t app, int keynumber, u32 timestamp, - const unsigned char *m, size_t mlen, - const unsigned char *e, size_t elen, - unsigned char *fpr, unsigned int card_version) + unsigned char *fpr, unsigned int card_version, + key_type_t key_type, + ...) { unsigned int n, nbits; unsigned char *buffer, *p; int tag, tag2; int rc; + const unsigned char *m[MAX_ARGS_STORE_FPR]; + size_t mlen[MAX_ARGS_STORE_FPR]; + va_list ap; + int argc; + int i; - for (; mlen && !*m; mlen--, m++) /* strip leading zeroes */ - ; - for (; elen && !*e; elen--, e++) /* strip leading zeroes */ - ; + n = 6; /* key packet version, 4-byte timestamps, and algorithm */ + if (key_type == KEY_TYPE_RSA || key_type == KEY_TYPE_ECDSA) + argc = 2; + else if (key_type == KEY_TYPE_ECDH) + argc = 3; + else + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + va_start (ap, key_type); + for (i = 0; i < argc; i++) + { + m[i] = va_arg (ap, const unsigned char *); + mlen[i] = va_arg (ap, size_t); + for (; mlen[i] && !*m[i]; mlen[i]--, m[i]++) /* strip leading zeroes */ + ; + if (key_type == KEY_TYPE_RSA || i == 1) + n += 2; + n += mlen[i]; + } + va_end (ap); - n = 6 + 2 + mlen + 2 + elen; p = buffer = xtrymalloc (3 + n); if (!buffer) return gpg_error_from_syserror (); @@ -765,15 +802,19 @@ store_fpr (app_t app, int keynumber, u32 timestamp, *p++ = timestamp >> 16; *p++ = timestamp >> 8; *p++ = timestamp; - *p++ = 1; /* RSA */ - nbits = count_bits (m, mlen); - *p++ = nbits >> 8; - *p++ = nbits; - memcpy (p, m, mlen); p += mlen; - nbits = count_bits (e, elen); - *p++ = nbits >> 8; - *p++ = nbits; - memcpy (p, e, elen); p += elen; + *p++ = get_algo_byte (key_type); + + for (i = 0; i < argc; i++) + { + if (key_type == KEY_TYPE_RSA || i == 1) + { + nbits = count_bits (m[i], mlen[i]); + *p++ = nbits >> 8; + *p++ = nbits; + } + memcpy (p, m[i], mlen[i]); + p += mlen[i]; + } gcry_md_hash_buffer (GCRY_MD_SHA1, fpr, buffer, n+3); @@ -889,11 +930,16 @@ get_ecc_key_parameters (int curve, int *r_n_bits, const char **r_curve_oid) *r_n_bits = 384; *r_curve_oid = "1.3.132.0.34"; } - else + else if (curve == CURVE_NIST_P521) { *r_n_bits = 521; *r_curve_oid = "1.3.132.0.35"; } + else + { + *r_n_bits = 256; + *r_curve_oid = "1.3.132.0.10"; + } } static void @@ -1234,8 +1280,10 @@ get_curve_name (int curve) return "NIST P-256"; else if (curve == CURVE_NIST_P384) return "NIST P-384"; - else + else if (curve == CURVE_NIST_P521) return "NIST P-521"; + else + return "secp256k1"; } @@ -1456,7 +1504,7 @@ get_public_key (app_t app, int keyno) = get_curve_name (app->app_local->keyattr[keyno].ecdsa.curve); err = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecdsa(curve%s)(q%b)))", + "(public-key(ecc(curve%s)(q%b)))", curve_name, mlen, mbuf); if (err) goto leave; @@ -2500,8 +2548,6 @@ add_tlv (unsigned char *buffer, unsigned int tag, size_t length) } -/* Build the private key template as specified in the OpenPGP specs - v2.0 section 4.3.3.7. */ static gpg_error_t build_privkey_template (app_t app, int keyno, const unsigned char *rsa_n, size_t rsa_n_len, @@ -2648,6 +2694,74 @@ build_privkey_template (app_t app, int keyno, return 0; } +static gpg_error_t +build_ecdsa_privkey_template (app_t app, int keyno, + const unsigned char *ecc_d, size_t ecc_d_len, + unsigned char **result, size_t *resultlen) +{ + unsigned char privkey[2]; + size_t privkey_len; + unsigned char exthdr[2+2+1]; + size_t exthdr_len; + unsigned char suffix[2+1]; + size_t suffix_len; + unsigned char *tp; + size_t datalen; + unsigned char *template; + size_t template_size; + + *result = NULL; + *resultlen = 0; + + /* Build the 7f48 cardholder private key template. */ + datalen = 0; + tp = privkey; + + tp += add_tlv (tp, 0x91, ecc_d_len); /* Tag 0x91??? */ + datalen += ecc_d_len; + + privkey_len = tp - privkey; + + /* Build the extended header list without the private key template. */ + tp = exthdr; + *tp++ = keyno ==0 ? 0xb6 : keyno == 1? 0xb8 : 0xa4; + *tp++ = 0; + tp += add_tlv (tp, 0x7f48, privkey_len); + exthdr_len = tp - exthdr; + + /* Build the 5f48 suffix of the data. */ + tp = suffix; + tp += add_tlv (tp, 0x5f48, datalen); + suffix_len = tp - suffix; + + /* Now concatenate everything. */ + template_size = (1 + 1 /* 0x4d and len. */ + + exthdr_len + + privkey_len + + suffix_len + + datalen); + tp = template = xtrymalloc_secure (template_size); + if (!template) + return gpg_error_from_syserror (); + + tp += add_tlv (tp, 0x4d, exthdr_len + privkey_len + suffix_len + datalen); + memcpy (tp, exthdr, exthdr_len); + tp += exthdr_len; + memcpy (tp, privkey, privkey_len); + tp += privkey_len; + memcpy (tp, suffix, suffix_len); + tp += suffix_len; + + memcpy (tp, ecc_d, ecc_d_len); + tp += ecc_d_len; + + assert (tp - template == template_size); + + *result = template; + *resultlen = tp - template; + return 0; +} + /* Helper for do_writekley to change the size of a key. Not ethat this deletes the entire key without asking. */ @@ -2749,26 +2863,15 @@ change_keyattr_from_string (app_t app, } -/* Handle the WRITEKEY command for OpenPGP. This function expects a - canonical encoded S-expression with the secret key in KEYDATA and - its length (for assertions) in KEYDATALEN. KEYID needs to be the - usual keyid which for OpenPGP is the string "OPENPGP.n" with - n=1,2,3. Bit 0 of FLAGS indicates whether an existing key shall - get overwritten. PINCB and PINCB_ARG are the usual arguments for - the pinentry callback. */ static gpg_error_t -do_writekey (app_t app, ctrl_t ctrl, - const char *keyid, unsigned int flags, - gpg_error_t (*pincb)(void*, const char *, char **), - void *pincb_arg, - const unsigned char *keydata, size_t keydatalen) +rsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, int keyno, + const unsigned char *buf, size_t buflen, int depth) { gpg_error_t err; - int force = (flags & 1); - int keyno; - const unsigned char *buf, *tok; - size_t buflen, toklen; - int depth, last_depth1, last_depth2; + const unsigned char *tok; + size_t toklen; + int last_depth1, last_depth2; const unsigned char *rsa_n = NULL; const unsigned char *rsa_e = NULL; const unsigned char *rsa_p = NULL; @@ -2782,52 +2885,6 @@ do_writekey (app_t app, ctrl_t ctrl, unsigned char fprbuf[20]; u32 created_at = 0; - (void)ctrl; - - if (!strcmp (keyid, "OPENPGP.1")) - keyno = 0; - else if (!strcmp (keyid, "OPENPGP.2")) - keyno = 1; - else if (!strcmp (keyid, "OPENPGP.3")) - keyno = 2; - else - return gpg_error (GPG_ERR_INV_ID); - - err = does_key_exist (app, keyno, 0, force); - if (err) - return err; - - - /* - Parse the S-expression - */ - buf = keydata; - buflen = keydatalen; - depth = 0; - if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) - goto leave; - if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) - goto leave; - if (!tok || toklen != 11 || memcmp ("private-key", tok, toklen)) - { - if (!tok) - ; - else if (toklen == 21 && !memcmp ("protected-private-key", tok, toklen)) - log_info ("protected-private-key passed to writekey\n"); - else if (toklen == 20 && !memcmp ("shadowed-private-key", tok, toklen)) - log_info ("shadowed-private-key passed to writekey\n"); - err = gpg_error (GPG_ERR_BAD_SECKEY); - goto leave; - } - if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) - goto leave; - if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) - goto leave; - if (!tok || toklen != 3 || memcmp ("rsa", tok, toklen)) - { - err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO); - goto leave; - } last_depth1 = depth; while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) && depth && depth >= last_depth1) @@ -3100,9 +3157,198 @@ do_writekey (app_t app, ctrl_t ctrl, goto leave; } - err = store_fpr (app, keyno, created_at, - rsa_n, rsa_n_len, rsa_e, rsa_e_len, - fprbuf, app->card_version); + err = store_fpr (app, keyno, created_at, fprbuf, app->card_version, + KEY_TYPE_RSA, rsa_n, rsa_n_len, rsa_e, rsa_e_len); + if (err) + goto leave; + + + leave: + xfree (template); + return err; +} + + +static gpg_error_t +ecdh_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, int keyno, + const unsigned char *buf, size_t buflen, int depth) +{ + return GPG_ERR_NOT_IMPLEMENTED; +} + + +static gpg_error_t +ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, int keyno, + const unsigned char *buf, size_t buflen, int depth) +{ + gpg_error_t err; + const unsigned char *tok; + size_t toklen; + int last_depth1, last_depth2; + const unsigned char *ecc_q = NULL; + const unsigned char *ecc_d = NULL; + size_t ecc_q_len, ecc_d_len; + unsigned char *template = NULL; + size_t template_len; + unsigned char fprbuf[20]; + u32 created_at = 0; + int curve = CURVE_UNKOWN; + + /* (private-key(ecdsa(curve%s)(q%m)(d%m))): curve = "1.2.840.10045.3.1.7" */ + /* (private-key(ecc(curve%s)(q%m)(d%m))): curve = "secp256k1" */ + last_depth1 = depth; + while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) + && depth && depth >= last_depth1) + { + if (tok) + { + err = gpg_error (GPG_ERR_UNKNOWN_SEXP); + goto leave; + } + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + goto leave; + + if (tok && toklen == 5 && !memcmp (tok, "curve", 5)) + { + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + goto leave; + + if (tok && toklen == 19 && !memcmp (tok, "1.2.840.10045.3.1.7", 19)) + curve = CURVE_NIST_P256; + else if (tok && toklen == 9 && !memcmp (tok, "secp256k1", 9)) + curve = CURVE_SEC_P256K1; + } + else if (tok && toklen == 1) + { + const unsigned char **mpi; + size_t *mpi_len; + + switch (*tok) + { + case 'q': mpi = &ecc_q; mpi_len = &ecc_q_len; break; + case 'd': mpi = &ecc_d; mpi_len = &ecc_d_len; break; + default: mpi = NULL; mpi_len = NULL; break; + } + if (mpi && *mpi) + { + err = gpg_error (GPG_ERR_DUP_VALUE); + goto leave; + } + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + goto leave; + if (tok && mpi) + { + /* Strip off leading zero bytes and save. */ + for (;toklen && !*tok; toklen--, tok++) + ; + *mpi = tok; + *mpi_len = toklen; + } + } + /* Skip until end of list. */ + last_depth2 = depth; + while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) + && depth && depth >= last_depth2) + ; + if (err) + goto leave; + } + /* Parse other attributes. */ + last_depth1 = depth; + while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) + && depth && depth >= last_depth1) + { + if (tok) + { + err = gpg_error (GPG_ERR_UNKNOWN_SEXP); + goto leave; + } + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + goto leave; + if (tok && toklen == 10 && !memcmp ("created-at", tok, toklen)) + { + if ((err = parse_sexp (&buf,&buflen,&depth,&tok,&toklen))) + goto leave; + if (tok) + { + for (created_at=0; toklen && *tok && *tok >= '0' && *tok <= '9'; + tok++, toklen--) + created_at = created_at*10 + (*tok - '0'); + } + } + /* Skip until end of list. */ + last_depth2 = depth; + while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) + && depth && depth >= last_depth2) + ; + if (err) + goto leave; + } + + + /* Check that we have all parameters and that they match the card + description. */ + if (!created_at) + { + log_error (_("creation timestamp missing\n")); + err = gpg_error (GPG_ERR_INV_VALUE); + goto leave; + } + + if (opt.verbose) + log_info ("ECC private key size is %u bytes\n", (unsigned int)ecc_d_len); + + /* We need to remove the cached public key. */ + xfree (app->app_local->pk[keyno].key); + app->app_local->pk[keyno].key = NULL; + app->app_local->pk[keyno].keylen = 0; + app->app_local->pk[keyno].read_done = 0; + + if (app->app_local->extcap.is_v2) + { + /* Build the private key template as described in section 4.3.3.7 of + the OpenPGP card specs version 2.0. */ + int exmode; + + err = build_ecdsa_privkey_template (app, keyno, + ecc_d, ecc_d_len, + &template, &template_len); + if (err) + goto leave; + + /* Prepare for storing the key. */ + err = verify_chv3 (app, pincb, pincb_arg); + if (err) + goto leave; + + /* Store the key. */ + if (app->app_local->cardcap.ext_lc_le && template_len > 254) + exmode = 1; /* Use extended length w/o a limit. */ + else if (app->app_local->cardcap.cmd_chaining && template_len > 254) + exmode = -254; + else + exmode = 0; + err = iso7816_put_data_odd (app->slot, exmode, 0x3fff, + template, template_len); + } + else + return gpg_error (GPG_ERR_NOT_SUPPORTED); + + if (err) + { + log_error (_("failed to store the key: %s\n"), gpg_strerror (err)); + goto leave; + } + + err = store_fpr (app, keyno, created_at, fprbuf, app->card_version, + KEY_TYPE_ECDSA, + curve == CURVE_NIST_P256? + "\x08\x2a\x86\x48\xce\x3d\x03\x01\x07" + : "\05\x2b\x81\x04\x00\x0a", + curve == CURVE_NIST_P256? 9 : 6, + ecc_q, ecc_q_len); if (err) goto leave; @@ -3112,6 +3358,89 @@ do_writekey (app_t app, ctrl_t ctrl, return err; } +/* Handle the WRITEKEY command for OpenPGP. This function expects a + canonical encoded S-expression with the secret key in KEYDATA and + its length (for assertions) in KEYDATALEN. KEYID needs to be the + usual keyid which for OpenPGP is the string "OPENPGP.n" with + n=1,2,3. Bit 0 of FLAGS indicates whether an existing key shall + get overwritten. PINCB and PINCB_ARG are the usual arguments for + the pinentry callback. */ +static gpg_error_t +do_writekey (app_t app, ctrl_t ctrl, + const char *keyid, unsigned int flags, + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const unsigned char *keydata, size_t keydatalen) +{ + gpg_error_t err; + int force = (flags & 1); + int keyno; + const unsigned char *buf, *tok; + size_t buflen, toklen; + int depth; + + (void)ctrl; + + if (!strcmp (keyid, "OPENPGP.1")) + keyno = 0; + else if (!strcmp (keyid, "OPENPGP.2")) + keyno = 1; + else if (!strcmp (keyid, "OPENPGP.3")) + keyno = 2; + else + return gpg_error (GPG_ERR_INV_ID); + + err = does_key_exist (app, keyno, 0, force); + if (err) + return err; + + + /* + Parse the S-expression + */ + buf = keydata; + buflen = keydatalen; + depth = 0; + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + goto leave; + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + goto leave; + if (!tok || toklen != 11 || memcmp ("private-key", tok, toklen)) + { + if (!tok) + ; + else if (toklen == 21 && !memcmp ("protected-private-key", tok, toklen)) + log_info ("protected-private-key passed to writekey\n"); + else if (toklen == 20 && !memcmp ("shadowed-private-key", tok, toklen)) + log_info ("shadowed-private-key passed to writekey\n"); + err = gpg_error (GPG_ERR_BAD_SECKEY); + goto leave; + } + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + goto leave; + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + goto leave; + if (tok && toklen == 3 && memcmp ("rsa", tok, toklen) == 0) + rsa_writekey (app, pincb, pincb_arg, keyno, buf, buflen, depth); + else if ((tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0 + && (keyno == 0 || keyno == 2)) + || (tok && toklen == 5 && memcmp ("ecdsa", tok, toklen) == 0)) + ecdsa_writekey (app, pincb, pincb_arg, keyno, buf, buflen, depth); + else if ((tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0 + && keyno == 1) + || (tok && toklen == 4 && memcmp ("ecdh", tok, toklen) == 0)) + ecdh_writekey (app, pincb, pincb_arg, keyno, buf, buflen, depth); + else + { + err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO); + goto leave; + } + + leave: + return err; +} + + /* Handle the GENKEY command. */ static gpg_error_t @@ -3234,8 +3563,8 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, send_status_info (ctrl, "KEY-CREATED-AT", numbuf, (size_t)strlen(numbuf), NULL, 0); - rc = store_fpr (app, keyno, (u32)created_at, - m, mlen, e, elen, fprbuf, app->card_version); + rc = store_fpr (app, keyno, (u32)created_at, fprbuf, app->card_version, + KEY_TYPE_RSA, m, mlen, e, elen); if (rc) goto leave; send_fpr_if_not_null (ctrl, "KEY-FPR", -1, fprbuf); @@ -3973,8 +4302,10 @@ parse_ecc_curve (const unsigned char *buffer, size_t buflen) curve = CURVE_NIST_P384; else if (buflen == 6 && buffer[5] == 0x23) curve = CURVE_NIST_P521; - else + else if (buflen == 9) curve = CURVE_NIST_P256; + else + curve = CURVE_SEC_P256K1; return curve; } ----------------------------------------------------------------------- Summary of changes: scd/app-openpgp.c | 517 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 424 insertions(+), 93 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Wed Mar 12 14:33:18 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Wed, 12 Mar 2014 14:33:18 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-355-gfb56a27 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via fb56a273b1f2b3a99dc1d1a0850378ab7625e6b9 (commit) via 99135b89ced35d867dddadf9d51e63a3d8837fc3 (commit) via 3d9e0eb02ce2b2e153e25deb0fc4b27b45f5026a (commit) from 781b94174310dceffa075719420b74b29fe41764 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit fb56a273b1f2b3a99dc1d1a0850378ab7625e6b9 Author: Werner Koch Date: Wed Mar 12 14:32:34 2014 +0100 dirmngr: Detect dead keyservers and try another one. * dirmngr/ks-action.c (ks_action_resolve): Rename var for clarity. (ks_action_search, ks_action_put): Ditto. (ks_action_get): Consult only the first server which retruned some data. * dirmngr/ks-engine-hkp.c (SEND_REQUEST_RETRIES): New. (map_host): Add arg CTRL and call dirmngr_tick. (make_host_part): Add arg CTRL. (mark_host_dead): Allow the use of an URL. (handle_send_request_error): New. (ks_hkp_search, ks_hkp_get, ks_hkp_put): Mark host dead and retry on error. diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c index dfeb862..495f7fa 100644 --- a/dirmngr/ks-action.c +++ b/dirmngr/ks-action.c @@ -120,21 +120,21 @@ gpg_error_t ks_action_resolve (ctrl_t ctrl) { gpg_error_t err = 0; - int any = 0; + int any_server = 0; uri_item_t uri; for (uri = ctrl->keyservers; !err && uri; uri = uri->next) { if (uri->parsed_uri->is_http) { - any = 1; + any_server = 1; err = ks_hkp_resolve (ctrl, uri->parsed_uri); if (err) break; } } - if (!any) + if (!any_server) err = gpg_error (GPG_ERR_NO_KEYSERVER); return err; } @@ -146,7 +146,7 @@ gpg_error_t ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp) { gpg_error_t err = 0; - int any = 0; + int any_server = 0; uri_item_t uri; estream_t infp; @@ -163,7 +163,7 @@ ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp) { if (uri->parsed_uri->is_http) { - any = 1; + any_server = 1; err = ks_hkp_search (ctrl, uri->parsed_uri, patterns->d, &infp); if (!err) { @@ -174,7 +174,7 @@ ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp) } } - if (!any) + if (!any_server) err = gpg_error (GPG_ERR_NO_KEYSERVER); return err; } @@ -187,7 +187,8 @@ ks_action_get (ctrl_t ctrl, strlist_t patterns, estream_t outfp) { gpg_error_t err = 0; gpg_error_t first_err = 0; - int any = 0; + int any_server = 0; + int any_data = 0; strlist_t sl; uri_item_t uri; estream_t infp; @@ -205,7 +206,7 @@ ks_action_get (ctrl_t ctrl, strlist_t patterns, estream_t outfp) { if (uri->parsed_uri->is_http) { - any = 1; + any_server = 1; for (sl = patterns; !err && sl; sl = sl->next) { err = ks_hkp_get (ctrl, uri->parsed_uri, sl->d, &infp); @@ -224,17 +225,21 @@ ks_action_get (ctrl_t ctrl, strlist_t patterns, estream_t outfp) err = copy_stream (infp, outfp); /* Reading from the keyserver should never fail, thus return this error. */ + if (!err) + any_data = 1; es_fclose (infp); infp = NULL; } } } + if (any_data) + break; /* Stop loop after a keyserver returned something. */ } - if (!any) + if (!any_server) err = gpg_error (GPG_ERR_NO_KEYSERVER); - else if (!err && first_err) - err = first_err; /* fixme: Do we really want to do that? */ + else if (!err && first_err && !any_data) + err = first_err; return err; } @@ -302,14 +307,14 @@ ks_action_put (ctrl_t ctrl, const void *data, size_t datalen) { gpg_error_t err = 0; gpg_error_t first_err = 0; - int any = 0; + int any_server = 0; uri_item_t uri; for (uri = ctrl->keyservers; !err && uri; uri = uri->next) { if (uri->parsed_uri->is_http) { - any = 1; + any_server = 1; err = ks_hkp_put (ctrl, uri->parsed_uri, data, datalen); if (err) { @@ -319,9 +324,9 @@ ks_action_put (ctrl_t ctrl, const void *data, size_t datalen) } } - if (!any) + if (!any_server) err = gpg_error (GPG_ERR_NO_KEYSERVER); else if (!err && first_err) - err = first_err; /* fixme: Do we really want to do that? */ + err = first_err; return err; } diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 13da3cb..28b05e9 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -53,6 +53,9 @@ /* How many redirections do we allow. */ #define MAX_REDIRECTS 2 +/* Number of retries done for a dead host etc. */ +#define SEND_REQUEST_RETRIES 3 + /* Objects used to maintain information about hosts. */ struct hostinfo_s; typedef struct hostinfo_s *hostinfo_t; @@ -242,7 +245,7 @@ my_getnameinfo (const struct sockaddr *sa, socklen_t salen, independent of DNS retry times. If FORCE_RESELECT is true a new host is always selected. */ static char * -map_host (const char *name, int force_reselect) +map_host (ctrl_t ctrl, const char *name, int force_reselect) { hostinfo_t hi; int idx; @@ -291,6 +294,7 @@ map_host (const char *name, int force_reselect) if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) continue; + dirmngr_tick (ctrl); if ((ec = my_getnameinfo (ai->ai_addr, ai->ai_addrlen, tmphost, sizeof tmphost))) { @@ -401,22 +405,51 @@ map_host (const char *name, int force_reselect) } -/* Mark the host NAME as dead. */ -static void +/* Mark the host NAME as dead. NAME may be given as an URL. Returns + true if a host was really marked as dead or was already marked dead + (e.g. by a concurrent session). */ +static int mark_host_dead (const char *name) { - hostinfo_t hi; - int idx; + const char *host; + char *host_buffer = NULL; + parsed_uri_t parsed_uri = NULL; + int done = 0; - if (!name || !*name || !strcmp (name, "localhost")) - return; + if (name && *name && !http_parse_uri (&parsed_uri, name, 1)) + { + if (parsed_uri->v6lit) + { + host_buffer = strconcat ("[", parsed_uri->host, "]", NULL); + if (!host_buffer) + log_error ("out of core in mark_host_dead"); + host = host_buffer; + } + else + host = parsed_uri->host; + } + else + host = name; - idx = find_hostinfo (name); - if (idx == -1) - return; - hi = hosttable[idx]; - log_info ("marking host '%s' as dead%s\n", hi->name, hi->dead? " (again)":""); - hi->dead = 1; + if (host && *host && strcmp (host, "localhost")) + { + hostinfo_t hi; + int idx; + + idx = find_hostinfo (host); + if (idx != -1) + { + hi = hosttable[idx]; + log_info ("marking host '%s' as dead%s\n", + hi->name, hi->dead? " (again)":""); + hi->dead = 1; + done = 1; + } + } + + http_release_parsed_uri (parsed_uri); + xfree (host_buffer); + return done; } @@ -566,7 +599,8 @@ ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri) PORT. Returns an allocated string or NULL on failure and sets ERRNO. */ static char * -make_host_part (const char *scheme, const char *host, unsigned short port, +make_host_part (ctrl_t ctrl, + const char *scheme, const char *host, unsigned short port, int force_reselect) { char portstr[10]; @@ -591,7 +625,7 @@ make_host_part (const char *scheme, const char *host, unsigned short port, /*fixme_do_srv_lookup ()*/ } - hostname = map_host (host, force_reselect); + hostname = map_host (ctrl, host, force_reselect); if (!hostname) return NULL; @@ -610,7 +644,7 @@ ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri) gpg_error_t err; char *hostport = NULL; - hostport = make_host_part (uri->scheme, uri->host, uri->port, 1); + hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, 1); if (!hostport) { err = gpg_error_from_syserror (); @@ -746,6 +780,42 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr, } +/* Helper to evaluate the error code ERR form a send_request() call + with REQUEST. The function returns true if the caller shall try + again. TRIES_LEFT points to a variable to track the number of + retries; this function decrements it and won't return true if it is + down to zero. */ +static int +handle_send_request_error (gpg_error_t err, const char *request, + unsigned int *tries_left) +{ + int retry = 0; + + switch (gpg_err_code (err)) + { + case GPG_ERR_ECONNREFUSED: + case GPG_ERR_ENETUNREACH: + if (mark_host_dead (request) && *tries_left) + retry = 1; + break; + + case GPG_ERR_ETIMEDOUT: + if (*tries_left) + { + log_info ("selecting a different host due to a timeout\n"); + retry = 1; + } + + default: + break; + } + + if (*tries_left) + --*tries_left; + + return retry; +} + static gpg_error_t armor_data (char **r_string, const void *data, size_t datalen) { @@ -817,6 +887,8 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, char *hostport = NULL; char *request = NULL; estream_t fp = NULL; + int reselect; + unsigned int tries = SEND_REQUEST_RETRIES; *r_fp = NULL; @@ -858,10 +930,14 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, } /* Build the request string. */ + reselect = 0; + again: { char *searchkey; - hostport = make_host_part (uri->scheme, uri->host, uri->port, 0); + xfree (hostport); + hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, + reselect); if (!hostport) { err = gpg_error_from_syserror (); @@ -875,6 +951,7 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, goto leave; } + xfree (request); request = strconcat (hostport, "/pks/lookup?op=index&options=mr&search=", searchkey, @@ -889,6 +966,11 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, /* Send the request. */ err = send_request (ctrl, request, hostport, NULL, NULL, &fp); + if (handle_send_request_error (err, request, &tries)) + { + reselect = 1; + goto again; + } if (err) goto leave; @@ -935,6 +1017,8 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) char *hostport = NULL; char *request = NULL; estream_t fp = NULL; + int reselect; + unsigned int tries = SEND_REQUEST_RETRIES; *r_fp = NULL; @@ -966,14 +1050,18 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) return gpg_error (GPG_ERR_INV_USER_ID); } + reselect = 0; + again: /* Build the request string. */ - hostport = make_host_part (uri->scheme, uri->host, uri->port, 0); + xfree (hostport); + hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect); if (!hostport) { err = gpg_error_from_syserror (); goto leave; } + xfree (request); request = strconcat (hostport, "/pks/lookup?op=get&options=mr&search=0x", kidbuf, @@ -986,6 +1074,11 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) /* Send the request. */ err = send_request (ctrl, request, hostport, NULL, NULL, &fp); + if (handle_send_request_error (err, request, &tries)) + { + reselect = 1; + goto again; + } if (err) goto leave; @@ -1042,6 +1135,8 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen) estream_t fp = NULL; struct put_post_parm_s parm; char *armored = NULL; + int reselect; + unsigned int tries = SEND_REQUEST_RETRIES; parm.datastring = NULL; @@ -1059,13 +1154,17 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen) armored = NULL; /* Build the request string. */ - hostport = make_host_part (uri->scheme, uri->host, uri->port, 0); + reselect = 0; + again: + xfree (hostport); + hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect); if (!hostport) { err = gpg_error_from_syserror (); goto leave; } + xfree (request); request = strconcat (hostport, "/pks/add", NULL); if (!request) { @@ -1075,6 +1174,11 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen) /* Send the request. */ err = send_request (ctrl, request, hostport, put_post_cb, &parm, &fp); + if (handle_send_request_error (err, request, &tries)) + { + reselect = 1; + goto again; + } if (err) goto leave; commit 99135b89ced35d867dddadf9d51e63a3d8837fc3 Author: Werner Koch Date: Wed Mar 12 14:27:50 2014 +0100 Comment typo fixes -- diff --git a/dirmngr/server.c b/dirmngr/server.c index fb619df..a1d2033 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -2130,7 +2130,7 @@ dirmngr_status_help (ctrl_t ctrl, const char *text) return err; } -/* Send a tick progress indicator back. Fixme: This is only does for +/* Send a tick progress indicator back. Fixme: This is only done for the currently active channel. */ gpg_error_t dirmngr_tick (ctrl_t ctrl) diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c index 75f25f8..2310d8b 100644 --- a/g10/call-dirmngr.c +++ b/g10/call-dirmngr.c @@ -71,10 +71,10 @@ struct ks_put_parm_s /* Data used to associate an session with dirmngr contexts. We can't use a simple one to one mapping because we sometimes need two - connection s to the dirmngr; for example while doing a listing and + connections to the dirmngr; for example while doing a listing and being in a data callback we may want to retrieve a key. The local dirmngr data takes care of this. At the end of the session the - function dirmngr_deinit_session_data is called bu gpg.c to cleanup + function dirmngr_deinit_session_data is called by gpg.c to cleanup these resources. Note that gpg.h defines a typedef dirmngr_local_t for this structure. */ struct dirmngr_local_s @@ -109,9 +109,8 @@ gpg_dirmngr_deinit_session_data (ctrl_t ctrl) } -/* Try to connect to the Dirmngr via a socket or fork it off if - possible. Handle the server's initial greeting and set global - options. */ +/* Try to connect to the Dirmngr via a socket or spawn it if possible. + Handle the server's initial greeting and set global options. */ static gpg_error_t create_context (ctrl_t ctrl, assuan_context_t *r_ctx) { @@ -135,7 +134,9 @@ create_context (ctrl_t ctrl, assuan_context_t *r_ctx) /* Set all configured keyservers. We clear existing keyservers so that any keyserver configured in GPG overrides keyservers - possibly configured in Dirmngr. */ + possibly still configured in Dirmngr for the session (Note + that the keyserver list of a session in Dirmngr survives a + RESET. */ for (ksi = opt.keyserver; !err && ksi; ksi = ksi->next) { char *line; @@ -166,8 +167,8 @@ create_context (ctrl_t ctrl, assuan_context_t *r_ctx) /* Get a context for accessing dirmngr. If no context is available a - new one is created and - if requred - dirmngr started. On success - an assuan context is stored at R_CTX. This Context may only be + new one is created and - if required - dirmngr started. On success + an assuan context is stored at R_CTX. This context may only be released by means of close_context. Note that NULL is stored at R_CTX on error. */ static gpg_error_t @@ -199,7 +200,7 @@ open_context (ctrl_t ctrl, assuan_context_t *r_ctx) xfree (dml); return err; } - /* To be on the Pth thread safe site we need to add it to a + /* To be on the nPth thread safe site we need to add it to a list; this is far easier than to have a lock for this function. It should not happen anyway but the code is free because we need it for the is_active check above. */ diff --git a/g10/keyserver.c b/g10/keyserver.c index 28b4a10..b8ab81e 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -1650,13 +1650,16 @@ keyserver_put (ctrl_t ctrl, strlist_t keyspecs, } +/* Loop over all URLs in STRLIST and fetch the key that URL. Note + that the fetch operation ignores the configured key servers and + instead directly retrieves the keys. */ int keyserver_fetch (ctrl_t ctrl, strlist_t urilist) { gpg_error_t err; strlist_t sl; estream_t datastream; - unsigned int options = opt.keyserver_options.import_options; + unsigned int save_options = opt.keyserver_options.import_options; /* Switch on fast-import, since fetch can handle more than one import and we don't want each set to rebuild the trustdb. @@ -1686,7 +1689,7 @@ keyserver_fetch (ctrl_t ctrl, strlist_t urilist) es_fclose (datastream); } - opt.keyserver_options.import_options = options; + opt.keyserver_options.import_options = save_options; /* If the original options didn't have fast import, and the trustdb is dirty, rebuild. */ commit 3d9e0eb02ce2b2e153e25deb0fc4b27b45f5026a Author: Werner Koch Date: Wed Mar 12 14:26:41 2014 +0100 http: Add a flag to the URL parser indicating a literal v6 address. * common/http.h (struct parsed_uri_t): Add field v6lit. * common/http.c (do_parse_uri): Set v6lit. diff --git a/common/http.c b/common/http.c index d2f13e4..d95a2fb 100644 --- a/common/http.c +++ b/common/http.c @@ -781,6 +781,7 @@ do_parse_uri (parsed_uri_t uri, int only_local_part, int no_scheme_check) uri->use_tls = 0; uri->is_http = 0; uri->opaque = 0; + uri->v6lit = 0; /* A quick validity check. */ if (strspn (p, VALID_URI_CHARS) != n) @@ -841,6 +842,7 @@ do_parse_uri (parsed_uri_t uri, int only_local_part, int no_scheme_check) *p3++ = '\0'; /* worst case, uri->host should have length 0, points to \0 */ uri->host = p + 1; + uri->v6lit = 1; p = p3; } else diff --git a/common/http.h b/common/http.h index 75d64d1..bea9f07 100644 --- a/common/http.h +++ b/common/http.h @@ -51,6 +51,7 @@ struct parsed_uri_s unsigned int is_http:1; /* This is a HTTP style URI. */ unsigned int use_tls:1; /* Whether TLS should be used. */ unsigned int opaque:1;/* Unknown scheme; PATH has the rest. */ + unsigned int v6lit:1; /* Host was given as a literal v6 address. */ char *auth; /* username/password for basic auth. */ char *host; /* Host (converted to lowercase). */ unsigned short port; /* Port (always set if the host is set). */ ----------------------------------------------------------------------- Summary of changes: common/http.c | 2 + common/http.h | 1 + dirmngr/ks-action.c | 35 +++++++----- dirmngr/ks-engine-hkp.c | 142 ++++++++++++++++++++++++++++++++++++++++------- dirmngr/server.c | 2 +- g10/call-dirmngr.c | 19 ++++--- g10/keyserver.c | 7 ++- 7 files changed, 162 insertions(+), 46 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Wed Mar 12 15:57:21 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Wed, 12 Mar 2014 15:57:21 +0100 Subject: [git] GnuPG - branch, STABLE-BRANCH-2-0, updated. gnupg-2.0.22-16-gdc941bd Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, STABLE-BRANCH-2-0 has been updated via dc941bdaec29d2fc60e2bddf85e11568367f531c (commit) from 3ae90ff28c500967cb90b1176299d2ca01ef450f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit dc941bdaec29d2fc60e2bddf85e11568367f531c Author: Werner Koch Date: Wed Dec 14 18:56:10 2011 +0100 scd: Skip S/N reading for the "undefined" application. * scd/app.c (select_application): Skip serial number reading. -- (cherry picked from commit 792e137ec7997a0ff5c54ff970611238d28d4ba8) Resolved conflicts: scd/app.c: Take care of already changed geldkarte/dinsig order. diff --git a/scd/app.c b/scd/app.c index 8bdfefa..742f937 100644 --- a/scd/app.c +++ b/scd/app.c @@ -69,7 +69,7 @@ print_progress_line (void *opaque, const char *what, int pc, int cur, int tot) never shares a reader (while performing one command). Returns 0 on success; only then the unlock_reader function must be called after returning from the handler. */ -static gpg_error_t +static gpg_error_t lock_reader (int slot, ctrl_t ctrl) { gpg_error_t err; @@ -89,7 +89,7 @@ lock_reader (int slot, ctrl_t ctrl) lock_table[slot].app = NULL; lock_table[slot].last_app = NULL; } - + if (!pth_mutex_acquire (&lock_table[slot].lock, 0, NULL)) { err = gpg_error_from_syserror (); @@ -188,7 +188,7 @@ application_notify_card_reset (int slot) return; /* FIXME: We are ignoring any error value here. */ - lock_reader (slot, NULL); + lock_reader (slot, NULL); /* Mark application as non-reusable. */ if (lock_table[slot].app) @@ -204,10 +204,10 @@ application_notify_card_reset (int slot) lock_table[slot].last_app = NULL; deallocate_app (app); } - unlock_reader (slot); + unlock_reader (slot); } - + /* This function is used by the serialno command to check for an application conflict which may appear if the serialno command is used to request a specific application and the connection has @@ -241,11 +241,14 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) app_t app = NULL; unsigned char *result = NULL; size_t resultlen; + int want_undefined; (void)ctrl; *r_app = NULL; + want_undefined = (name && !strcmp (name, "undefined")); + err = lock_reader (slot, ctrl); if (err) return err; @@ -287,7 +290,7 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) lock_table[slot].app = app; lock_table[slot].last_app = NULL; } - else + else { /* No, this saved application can't be used - deallocate it. */ lock_table[slot].last_app = NULL; @@ -309,7 +312,7 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) unlock_reader (slot); return 0; /* Okay: We share that one. */ } - + /* Need to allocate a new one. */ app = xtrycalloc (1, sizeof *app); if (!app) @@ -325,54 +328,66 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) /* Fixme: We should now first check whether a card is at all present. */ - /* Try to read the GDO file first to get a default serial number. */ - err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL); - if (!err) - err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL); - if (!err) - err = iso7816_read_binary (slot, 0, 0, &result, &resultlen); - if (!err) + /* Try to read the GDO file first to get a default serial number. + We skip this if the undefined application has been requested. */ + if (!want_undefined) { - size_t n; - const unsigned char *p; - - p = find_tlv_unchecked (result, resultlen, 0x5A, &n); - if (p) - resultlen -= (p-result); - if (p && n > resultlen && n == 0x0d && resultlen+1 == n) + err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL); + if (!err) + err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL); + if (!err) + err = iso7816_read_binary (slot, 0, 0, &result, &resultlen); + if (!err) { - /* The object it does not fit into the buffer. This is an - invalid encoding (or the buffer is too short. However, I - have some test cards with such an invalid encoding and - therefore I use this ugly workaround to return something - I can further experiment with. */ - log_info ("enabling BMI testcard workaround\n"); - n--; + size_t n; + const unsigned char *p; + + p = find_tlv_unchecked (result, resultlen, 0x5A, &n); + if (p) + resultlen -= (p-result); + if (p && n > resultlen && n == 0x0d && resultlen+1 == n) + { + /* The object it does not fit into the buffer. This is an + invalid encoding (or the buffer is too short. However, I + have some test cards with such an invalid encoding and + therefore I use this ugly workaround to return something + I can further experiment with. */ + log_info ("enabling BMI testcard workaround\n"); + n--; + } + + if (p && n <= resultlen) + { + /* The GDO file is pretty short, thus we simply reuse it for + storing the serial number. */ + memmove (result, p, n); + app->serialno = result; + app->serialnolen = n; + err = app_munge_serialno (app); + if (err) + goto leave; + } + else + xfree (result); + result = NULL; } - - if (p && n <= resultlen) - { - /* The GDO file is pretty short, thus we simply reuse it for - storing the serial number. */ - memmove (result, p, n); - app->serialno = result; - app->serialnolen = n; - err = app_munge_serialno (app); - if (err) - goto leave; - } - else - xfree (result); - result = NULL; } /* For certain error codes, there is no need to try more. */ if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT || gpg_err_code (err) == GPG_ERR_ENODEV) goto leave; - + /* Figure out the application to use. */ - err = gpg_error (GPG_ERR_NOT_FOUND); + if (want_undefined) + { + /* We switch to the "undefined" application only if explicitly + requested. */ + app->apptype = "UNDEFINED"; + err = 0; + } + else + err = gpg_error (GPG_ERR_NOT_FOUND); if (err && is_app_allowed ("openpgp") && (!name || !strcmp (name, "openpgp"))) @@ -428,10 +443,10 @@ get_supported_applications (void) int idx; size_t nbytes; char *buffer, *p; - + for (nbytes=1, idx=0; list[idx]; idx++) nbytes += strlen (list[idx]) + 1 + 1; - + buffer = xtrymalloc (nbytes); if (!buffer) return NULL; @@ -508,22 +523,22 @@ release_application (app_t app) /* The serial number may need some cosmetics. Do it here. This function shall only be called once after a new serial number has - been put into APP->serialno. + been put into APP->serialno. Prefixes we use: - + FF 00 00 = For serial numbers starting with an FF FF 01 00 = Some german p15 cards return an empty serial number so the serial number from the EF(TokenInfo) is used instead. FF 7F 00 = No serialno. - + All other serial number not starting with FF are used as they are. */ gpg_error_t app_munge_serialno (app_t app) { if (app->serialnolen && app->serialno[0] == 0xff) - { + { /* The serial number starts with our special prefix. This requires that we put our default prefix "FF0000" in front. */ unsigned char *p = xtrymalloc (app->serialnolen + 3); @@ -536,7 +551,7 @@ app_munge_serialno (app_t app) app->serialno = p; } else if (!app->serialnolen) - { + { unsigned char *p = xtrymalloc (3); if (!p) return gpg_error_from_syserror (); @@ -556,7 +571,7 @@ app_munge_serialno (app_t app) no update time is available the returned value is 0. Caller must free SERIAL unless the function returns an error. If STAMP is not of interest, NULL may be passed. */ -gpg_error_t +gpg_error_t app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp) { char *buf; @@ -639,7 +654,7 @@ app_readcert (app_t app, const char *certid, code returned. This function might not be supported by all applications. */ -gpg_error_t +gpg_error_t app_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) { gpg_error_t err; @@ -665,7 +680,7 @@ app_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) /* Perform a GETATTR operation. */ -gpg_error_t +gpg_error_t app_getattr (app_t app, ctrl_t ctrl, const char *name) { gpg_error_t err; @@ -686,7 +701,7 @@ app_getattr (app_t app, ctrl_t ctrl, const char *name) char *serial; time_t stamp; int rc; - + rc = app_get_serial_and_stamp (app, &serial, &stamp); if (rc) return rc; @@ -706,7 +721,7 @@ app_getattr (app_t app, ctrl_t ctrl, const char *name) } /* Perform a SETATTR operation. */ -gpg_error_t +gpg_error_t app_setattr (app_t app, const char *name, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, @@ -731,7 +746,7 @@ app_setattr (app_t app, const char *name, /* Create the signature and return the allocated result in OUTDATA. If a PIN is required the PINCB will be used to ask for the PIN; it should return the PIN in an allocated buffer and put it into PIN. */ -gpg_error_t +gpg_error_t app_sign (app_t app, const char *keyidstr, int hashalgo, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, @@ -763,7 +778,7 @@ app_sign (app_t app, const char *keyidstr, int hashalgo, return the allocated result in OUTDATA. If a PIN is required the PINCB will be used to ask for the PIN; it should return the PIN in an allocated buffer and put it into PIN. */ -gpg_error_t +gpg_error_t app_auth (app_t app, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, @@ -795,7 +810,7 @@ app_auth (app_t app, const char *keyidstr, /* Decrypt the data in INDATA and return the allocated result in OUTDATA. If a PIN is required the PINCB will be used to ask for the PIN; it should return the PIN in an allocated buffer and put it into PIN. */ -gpg_error_t +gpg_error_t app_decipher (app_t app, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, @@ -881,7 +896,7 @@ app_writekey (app_t app, ctrl_t ctrl, /* Perform a SETATTR operation. */ -gpg_error_t +gpg_error_t app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, time_t createtime, gpg_error_t (*pincb)(void*, const char *, char **), @@ -898,7 +913,7 @@ app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, err = lock_reader (app->slot, ctrl); if (err) return err; - err = app->fnc.genkey (app, ctrl, keynostr, flags, + err = app->fnc.genkey (app, ctrl, keynostr, flags, createtime, pincb, pincb_arg); unlock_reader (app->slot); if (opt.verbose) @@ -930,7 +945,7 @@ app_get_challenge (app_t app, size_t nbytes, unsigned char *buffer) /* Perform a CHANGE REFERENCE DATA or RESET RETRY COUNTER operation. */ -gpg_error_t +gpg_error_t app_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) @@ -958,7 +973,7 @@ app_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, /* Perform a VERIFY operation without doing anything lese. This may be used to initialze a the PIN cache for long lasting other operations. Its use is highly application dependent. */ -gpg_error_t +gpg_error_t app_check_pin (app_t app, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) ----------------------------------------------------------------------- Summary of changes: scd/app.c | 143 ++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 79 insertions(+), 64 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Thu Mar 13 12:06:08 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 13 Mar 2014 12:06:08 +0100 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.6.0-60-g50aeee5 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 50aeee51a0b1a09dd9fff2bb71749a816fe7a791 (commit) from 5a8e1504bf8a2ffbc018be576dea77b685200444 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 50aeee51a0b1a09dd9fff2bb71749a816fe7a791 Author: Werner Koch Date: Thu Mar 13 12:06:55 2014 +0100 tests: Print diagnostics for skipped tests. * tests/basic.c (show_note): New. (show_md_not_available): (show_old_hmac_not_available): (show_mac_not_available): (check_digests): Remove USE_foo cpp tests from the test table. Call show_md_not_available if algo is not available. (check_hmac): Likewise. (check_mac): Likewise. Signed-off-by: Werner Koch diff --git a/tests/basic.c b/tests/basic.c index 0eb0f77..5c6c51c 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -34,6 +34,7 @@ # define DIM(v) (sizeof(v)/sizeof((v)[0])) #endif +#define PGM "basic" typedef struct test_spec_pubkey_key { @@ -118,6 +119,82 @@ show_sexp (const char *prefix, gcry_sexp_t a) } +static void +show_note (const char *format, ...) +{ + va_list arg_ptr; + + if (!verbose && getenv ("srcdir")) + fputs (" ", stderr); /* To align above "PASS: ". */ + else + fprintf (stderr, "%s: ", PGM); + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + if (*format && format[strlen(format)-1] != '\n') + putc ('\n', stderr); + va_end (arg_ptr); +} + + +static void +show_md_not_available (int algo) +{ + static int list[100]; + static int listlen; + int i; + + if (!verbose && algo == GCRY_MD_MD2) + return; /* Do not print the diagnostic for that one. */ + + for (i=0; i < listlen; i++) + if (algo == list[i]) + return; /* Note already printed. */ + if (listlen < DIM (list)) + list[listlen++] = algo; + show_note ("hash algorithm %d not available - skipping tests", algo); +} + + +static void +show_old_hmac_not_available (int algo) +{ + static int list[100]; + static int listlen; + int i; + + if (!verbose && algo == GCRY_MD_MD2) + return; /* Do not print the diagnostic for that one. */ + + for (i=0; i < listlen; i++) + if (algo == list[i]) + return; /* Note already printed. */ + if (listlen < DIM (list)) + list[listlen++] = algo; + show_note ("hash algorithm %d for old HMAC API not available " + "- skipping tests", algo); +} + + +static void +show_mac_not_available (int algo) +{ + static int list[100]; + static int listlen; + int i; + + if (!verbose && algo == GCRY_MD_MD2) + return; /* Do not print the diagnostic for that one. */ + + for (i=0; i < listlen; i++) + if (algo == list[i]) + return; /* Note already printed. */ + if (listlen < DIM (list)) + list[listlen++] = algo; + show_note ("MAC algorithm %d not available - skipping tests", algo); +} + + + #define MAX_DATA_LEN 100 void @@ -4006,7 +4083,6 @@ check_digests (void) "\x29\x05\x7F\xD8\x6B\x20\xBF\xD6\x2D\xEC\xA0\xF1\xCC\xEA\x4A\xF5" "\x1F\xC1\x54\x90\xED\xDC\x47\xAF\x32\xBB\x2B\x66\xC3\x4F\xF9\xAD" "\x8C\x60\x08\xAD\x67\x7F\x77\x12\x69\x53\xB2\x26\xE4\xED\x8B\x01" }, -#ifdef USE_GOST_R_3411_94 { GCRY_MD_GOSTR3411_94, "This is message, length=32 bytes", "\xB1\xC4\x66\xD3\x75\x19\xB8\x2E\x83\x19\x81\x9F\xF3\x25\x95\xE0" @@ -4023,8 +4099,6 @@ check_digests (void) "!", "\x5C\x00\xCC\xC2\x73\x4C\xDD\x33\x32\xD3\xD4\x74\x95\x76\xE3\xC1" "\xA7\xDB\xAF\x0E\x7E\xA7\x4E\x9F\xA6\x02\x41\x3C\x90\xA1\x29\xFA" }, -#endif -#ifdef USE_GOST_R_3411_12 { GCRY_MD_STRIBOG512, "012345678901234567890123456789012345678901234567890123456789012", "\x1b\x54\xd0\x1a\x4a\xf5\xb9\xd5\xcc\x3d\x86\xd6\x8d\x28\x54\x62" @@ -4053,7 +4127,6 @@ check_digests (void) "\x20\xc8\xe3\xee\xf0\xe5\xe2\xfb", "\x9d\xd2\xfe\x4e\x90\x40\x9e\x5d\xa8\x7f\x53\x97\x6d\x74\x05\xb0" "\xc0\xca\xc6\x28\xfc\x66\x9a\x74\x1d\x50\x06\x3c\x55\x7e\x8f\x50" }, -#endif { 0 } }; gcry_error_t err; @@ -4064,6 +4137,11 @@ check_digests (void) for (i = 0; algos[i].md; i++) { + if (gcry_md_test_algo (algos[i].md)) + { + show_md_not_available (algos[i].md); + continue; + } if ((gcry_md_test_algo (algos[i].md) || algos[i].md == GCRY_MD_MD5) && in_fips_mode) { @@ -4488,6 +4566,11 @@ check_hmac (void) for (i = 0; algos[i].md; i++) { + if (gcry_md_test_algo (algos[i].md)) + { + show_old_hmac_not_available (algos[i].md); + continue; + } if ((gcry_md_test_algo (algos[i].md) || algos[i].md == GCRY_MD_MD5) && in_fips_mode) { @@ -5091,6 +5174,11 @@ check_mac (void) for (i = 0; algos[i].algo; i++) { + if (gcry_mac_test_algo (algos[i].algo)) + { + show_mac_not_available (algos[i].algo); + continue; + } if ((gcry_mac_test_algo (algos[i].algo) || algos[i].algo == GCRY_MAC_HMAC_MD5) && in_fips_mode) { ----------------------------------------------------------------------- Summary of changes: tests/basic.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 92 insertions(+), 4 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org From cvs at cvs.gnupg.org Thu Mar 13 14:23:31 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 13 Mar 2014 14:23:31 +0100 Subject: [git] GPGME - branch, master, updated. gpgme-1.4.2-26-g766355b Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 766355b5d4f63261c428531fdbdafb8b67de9369 (commit) from dd9c8c56719db093b8daa23aa40b2be71bbd1526 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 766355b5d4f63261c428531fdbdafb8b67de9369 Author: Werner Koch Date: Thu Mar 13 14:24:14 2014 +0100 Add configure option --enable-fixed-path. * configure.ac: Add option --enable-fixed-path. (FIXED_SEARCH_PATH): New ac_define. * src/posix-util.c (walk_path): Make use of the option. Remove current directory from fallback PATH. -- Note that using this option PATH is entirely ignored by GPGME and only the given value is used instead to locate the GnuPG binaries. On Android the use of PATH is not desirable. Instead the GnuPG tools are expected in a fixed directory. By using ./configure --enable-fixed-path="/foo/bar" gpg et al are expected to be installed as /foo/bar/gpg. With ./configure --enable-fixed-path="/foo/bar:/bin" gpg is expected as /foo/bar/gpg or /bin/gpg. diff --git a/configure.ac b/configure.ac index 21951fe..1111849 100644 --- a/configure.ac +++ b/configure.ac @@ -236,6 +236,17 @@ AM_CONDITIONAL(BUILD_W32_QT, test "$build_w32_qt" = yes) AM_CONDITIONAL(HAVE_PTHREAD, test "$have_pthread" = "yes") +AC_ARG_ENABLE([fixed-path], + AC_HELP_STRING([--enable-fixed-path=PATH], + [locate binaries only via this PATH]), + [fixed_search_path="$enableval"], + [fixed_search_path=""]) +if test x$fixed_search_path != x ; then + AC_DEFINE_UNQUOTED(FIXED_SEARCH_PATH, "$fixed_search_path", + [Locate binaries only via this PATH]) +fi + + # # Provide information about the build. # diff --git a/src/posix-util.c b/src/posix-util.c index 1b92ec1..e78cd77 100644 --- a/src/posix-util.c +++ b/src/posix-util.c @@ -78,9 +78,13 @@ walk_path (const char *pgm) const char *orig_path, *path, *s; char *fname, *p; +#ifdef FIXED_SEARCH_PATH + orig_path = FIXED_SEARCH_PATH; +#else orig_path = getenv ("PATH"); if (!orig_path) - orig_path = "/bin:/usr/bin:."; + orig_path = "/bin:/usr/bin"; +#endif fname = malloc (strlen (orig_path) + 1 + strlen (pgm) + 1); if (!fname) ----------------------------------------------------------------------- Summary of changes: configure.ac | 11 +++++++++++ src/posix-util.c | 6 +++++- 2 files changed, 16 insertions(+), 1 deletion(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Fri Mar 14 17:00:58 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Fri, 14 Mar 2014 17:00:58 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-360-g59b4fb5 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 59b4fb5f4927908af06bb80ecd86adbf6e54ba14 (commit) via d7fbefeb82833db9eea8b15dc7889ecf0b7ffab4 (commit) via a401f768ca8e218eef7a5c87a8f99cb1d6b4aaeb (commit) via 5d321eb00be0774418de1a05678ac0ec44d7193b (commit) via 6dd5d99a61f24aff862ccba9f7410d7f1af87c05 (commit) from fb56a273b1f2b3a99dc1d1a0850378ab7625e6b9 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 59b4fb5f4927908af06bb80ecd86adbf6e54ba14 Author: Werner Koch Date: Fri Mar 14 17:00:10 2014 +0100 dirmngr: Make use of IPv4 and IPV6 more explicit. * common/http.c (connect_server): Handle the new flags. * common/http.h (HTTP_FLAG_IGNORE_IPv4, HTTP_FLAG_IGNORE_IPv4): New. * dirmngr/ks-engine-hkp.c (map_host): Add arg r_httpflags. (make_host_part): Ditto. (send_request): Add arg httpflags. (ks_hkp_search, ks_hkp_get, ks_hkp_put): Handle httpflags. diff --git a/common/http.c b/common/http.c index d95a2fb..5410141 100644 --- a/common/http.c +++ b/common/http.c @@ -1,6 +1,7 @@ /* http.c - HTTP protocol handler * Copyright (C) 1999, 2001, 2002, 2003, 2004, 2006, 2009, 2010, * 2011 Free Software Foundation, Inc. + * Copyright (C) 2014 Werner Koch * * This file is part of GnuPG. * @@ -1706,8 +1707,6 @@ connect_server (const char *server, unsigned short port, #ifdef HAVE_W32_SYSTEM unsigned long inaddr; #endif - /* Not currently using the flags */ - (void)flags; *r_host_not_found = 0; #ifdef HAVE_W32_SYSTEM @@ -1790,6 +1789,11 @@ connect_server (const char *server, unsigned short port, for (ai = res; ai && !connected; ai = ai->ai_next) { + if (ai->ai_family == AF_INET && (flags & HTTP_FLAG_IGNORE_IPv4)) + continue; + if (ai->ai_family == AF_INET6 && (flags & HTTP_FLAG_IGNORE_IPv6)) + continue; + if (sock != -1) sock_close (sock); sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol); diff --git a/common/http.h b/common/http.h index bea9f07..224128b 100644 --- a/common/http.h +++ b/common/http.h @@ -74,10 +74,12 @@ http_req_t; /* We put the flag values into an enum, so that gdb can display them. */ enum { - HTTP_FLAG_TRY_PROXY = 1, - HTTP_FLAG_SHUTDOWN = 2, - HTTP_FLAG_LOG_RESP = 8, - HTTP_FLAG_IGNORE_CL = 32 + HTTP_FLAG_TRY_PROXY = 1, /* Try to use a proxy. */ + HTTP_FLAG_SHUTDOWN = 2, /* Close sending end after the request. */ + HTTP_FLAG_LOG_RESP = 8, /* Log the server respone. */ + HTTP_FLAG_IGNORE_CL = 32, /* Ignore content-length. */ + HTTP_FLAG_IGNORE_IPv4 = 64, /* Do not use IPv4. */ + HTTP_FLAG_IGNORE_IPv6 = 128 /* Do not use IPv6. */ }; struct http_context_s; diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 0b2850c..7b67302 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -249,13 +249,18 @@ my_getnameinfo (struct addrinfo *ai, char *host, size_t hostlen) to choose one of the hosts. For example we skip those hosts which failed for some time and we stick to one host for a time independent of DNS retry times. If FORCE_RESELECT is true a new - host is always selected. */ + host is always selected. If R_HTTPFLAGS is not NULL if will + received flags which are to be passed to http_open. */ static char * -map_host (ctrl_t ctrl, const char *name, int force_reselect) +map_host (ctrl_t ctrl, const char *name, int force_reselect, + unsigned int *r_httpflags) { hostinfo_t hi; int idx; + if (r_httpflags) + *r_httpflags = 0; + /* No hostname means localhost. */ if (!name || !*name) return xtrystrdup ("localhost"); @@ -406,6 +411,18 @@ map_host (ctrl_t ctrl, const char *name, int force_reselect) return NULL; } + if (r_httpflags) + { + /* If the hosttable does not indicate that a certain host + supports IPv, we explicit set the corresponding http + flags. The reason for this is that a host might be listed in + a pool as not v6 only but actually support v6 when later + resolved the name is resolved by our http layer. */ + if (!hi->v4) + *r_httpflags |= HTTP_FLAG_IGNORE_IPv4; + if (!hi->v6) + *r_httpflags |= HTTP_FLAG_IGNORE_IPv6; + } return xtrystrdup (hi->name); } @@ -605,7 +622,7 @@ ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri) static char * make_host_part (ctrl_t ctrl, const char *scheme, const char *host, unsigned short port, - int force_reselect) + int force_reselect, unsigned int *r_httpflags) { char portstr[10]; char *hostname; @@ -629,7 +646,7 @@ make_host_part (ctrl_t ctrl, /*fixme_do_srv_lookup ()*/ } - hostname = map_host (ctrl, host, force_reselect); + hostname = map_host (ctrl, host, force_reselect, r_httpflags); if (!hostname) return NULL; @@ -648,7 +665,7 @@ ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri) gpg_error_t err; char *hostport = NULL; - hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, 1); + hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, 1, NULL); if (!hostport) { err = gpg_error_from_syserror (); @@ -671,6 +688,7 @@ ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri) writing the post data. */ static gpg_error_t send_request (ctrl_t ctrl, const char *request, const char *hostportstr, + unsigned int httpflags, gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value, estream_t *r_fp) { @@ -687,7 +705,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr, post_cb? HTTP_REQ_POST : HTTP_REQ_GET, request, /* fixme: AUTH */ NULL, - 0, + httpflags, /* fixme: proxy*/ NULL, NULL, NULL, /*FIXME curl->srvtag*/NULL); @@ -892,6 +910,7 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, char *request = NULL; estream_t fp = NULL; int reselect; + unsigned int httpflags; unsigned int tries = SEND_REQUEST_RETRIES; *r_fp = NULL; @@ -941,7 +960,7 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, xfree (hostport); hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, - reselect); + reselect, &httpflags); if (!hostport) { err = gpg_error_from_syserror (); @@ -969,7 +988,7 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, } /* Send the request. */ - err = send_request (ctrl, request, hostport, NULL, NULL, &fp); + err = send_request (ctrl, request, hostport, httpflags, NULL, NULL, &fp); if (handle_send_request_error (err, request, &tries)) { reselect = 1; @@ -1026,6 +1045,7 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) char *request = NULL; estream_t fp = NULL; int reselect; + unsigned int httpflags; unsigned int tries = SEND_REQUEST_RETRIES; *r_fp = NULL; @@ -1062,7 +1082,8 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) again: /* Build the request string. */ xfree (hostport); - hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect); + hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, + reselect, &httpflags); if (!hostport) { err = gpg_error_from_syserror (); @@ -1081,7 +1102,7 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) } /* Send the request. */ - err = send_request (ctrl, request, hostport, NULL, NULL, &fp); + err = send_request (ctrl, request, hostport, httpflags, NULL, NULL, &fp); if (handle_send_request_error (err, request, &tries)) { reselect = 1; @@ -1148,6 +1169,7 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen) struct put_post_parm_s parm; char *armored = NULL; int reselect; + unsigned int httpflags; unsigned int tries = SEND_REQUEST_RETRIES; parm.datastring = NULL; @@ -1169,7 +1191,8 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen) reselect = 0; again: xfree (hostport); - hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect); + hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, + reselect, &httpflags); if (!hostport) { err = gpg_error_from_syserror (); @@ -1185,7 +1208,7 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen) } /* Send the request. */ - err = send_request (ctrl, request, hostport, put_post_cb, &parm, &fp); + err = send_request (ctrl, request, hostport, 0, put_post_cb, &parm, &fp); if (handle_send_request_error (err, request, &tries)) { reselect = 1; commit d7fbefeb82833db9eea8b15dc7889ecf0b7ffab4 Author: Werner Koch Date: Fri Mar 14 16:22:54 2014 +0100 dirmngr: Do not use brackets around legacy IP addresses. * dirmngr/ks-engine-hkp.c (my_getnameinfo): Change args to take a complete addrinfo. Bracket only v6 addresses. Change caller. diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 5c45435..0b2850c 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -214,23 +214,29 @@ select_random_host (int *table) for TMPHOST which is 2 bytes larger than the the largest hostname. returns 0 on success or an EAI error code. */ static int -my_getnameinfo (const struct sockaddr *sa, socklen_t salen, - char *host, size_t hostlen) +my_getnameinfo (struct addrinfo *ai, char *host, size_t hostlen) { int ec; + char *p; if (hostlen < 5) return EAI_OVERFLOW; - ec = getnameinfo (sa, salen, host, hostlen, NULL, 0, NI_NAMEREQD); + ec = getnameinfo (ai->ai_addr, ai->ai_addrlen, + host, hostlen, NULL, 0, NI_NAMEREQD); if (!ec && *host == '[') ec = EAI_FAIL; /* A name may never start with a bracket. */ else if (ec == EAI_NONAME) { - *host = '['; - ec = getnameinfo (sa, salen, host + 1, hostlen - 2, - NULL, 0, NI_NUMERICHOST); - if (!ec) + p = host; + if (ai->ai_family == AF_INET6) + { + *p++ = '['; + hostlen -= 2; + } + ec = getnameinfo (ai->ai_addr, ai->ai_addrlen, + p, hostlen, NULL, 0, NI_NUMERICHOST); + if (!ec && ai->ai_family == AF_INET6) strcat (host, "]"); } @@ -295,8 +301,7 @@ map_host (ctrl_t ctrl, const char *name, int force_reselect) continue; dirmngr_tick (ctrl); - if ((ec = my_getnameinfo (ai->ai_addr, ai->ai_addrlen, - tmphost, sizeof tmphost))) + if ((ec = my_getnameinfo (ai, tmphost, sizeof tmphost))) { log_info ("getnameinfo failed while checking '%s': %s\n", name, gai_strerror (ec)); commit a401f768ca8e218eef7a5c87a8f99cb1d6b4aaeb Author: Werner Koch Date: Fri Mar 14 16:12:54 2014 +0100 gpg: Print the actual used keyserver address. * dirmngr/ks-engine-hkp.c (ks_hkp_search, ks_hkp_get): Print SOURCE status lines. * g10/call-dirmngr.c (ks_status_parm_s): New. (ks_search_parm_s): Add field stparm. (ks_status_cb): New. (ks_search_data_cb): Send source to the data callback. (gpg_dirmngr_ks_search): Change callback prototope to include the SPECIAL arg. Adjust all users. Use ks_status_cb. (gpg_dirmngr_ks_get): Add arg r_source and use ks_status_cb. * g10/keyserver.c (search_line_handler): Adjust callback and print "data source" disgnostic. (keyserver_get): Print data source diagnostic. -- It has often been requested that the actually used IP of a keyservers is shown in with gpg --recv-key and --search-key. This is helpful if the keyserver is actually a pool of keyservers. This patch does this. diff --git a/common/stringhelp.c b/common/stringhelp.c index 2d2b412..7cbf82c 100644 --- a/common/stringhelp.c +++ b/common/stringhelp.c @@ -77,7 +77,7 @@ change_slashes (char *name) /* - * Check whether STRINGS starts with KEYWORD. The keyword is + * Check whether STRING starts with KEYWORD. The keyword is * delimited by end of string, a space or a tab. Returns NULL if not * found or a pointer into STRING to the next non-space character * after the KEYWORD (which may be end of string). diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 28b05e9..5c45435 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -454,8 +454,7 @@ mark_host_dead (const char *name) /* Mark a host in the hosttable as dead or - if ALIVE is true - as - alive. If the host NAME does not exist a warning status message is - printed. */ + alive. */ gpg_error_t ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive) { @@ -974,6 +973,10 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, if (err) goto leave; + err = dirmngr_status (ctrl, "SOURCE", hostport, NULL); + if (err) + goto leave; + /* Peek at the response. */ { int c = es_getc (fp); @@ -1082,6 +1085,10 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) if (err) goto leave; + err = dirmngr_status (ctrl, "SOURCE", hostport, NULL); + if (err) + goto leave; + /* Return the read stream and close the HTTP context. */ *r_fp = fp; fp = NULL; diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c index 9935333..73f829e 100644 --- a/g10/call-dirmngr.c +++ b/g10/call-dirmngr.c @@ -40,6 +40,13 @@ #include "call-dirmngr.h" +/* Parameter structure used to gather status info. */ +struct ks_status_parm_s +{ + char *source; +}; + + /* Parameter structure used with the KS_SEARCH command. */ struct ks_search_parm_s { @@ -47,8 +54,9 @@ struct ks_search_parm_s membuf_t saveddata; /* Buffer to build complete lines. */ char *helpbuf; /* NULL or malloced buffer. */ size_t helpbufsize; /* Allocated size of HELPBUF. */ - gpg_error_t (*data_cb)(void*, char*); /* Callback. */ + gpg_error_t (*data_cb)(void*, int, char*); /* Callback. */ void *data_cb_value; /* First argument for DATA_CB. */ + struct ks_status_parm_s *stparm; /* Link to the status parameter. */ }; @@ -235,6 +243,29 @@ close_context (ctrl_t ctrl, assuan_context_t ctx) +/* Status callback for ks_get and ks_search. */ +static gpg_error_t +ks_status_cb (void *opaque, const char *line) +{ + struct ks_status_parm_s *parm = opaque; + gpg_error_t err = 0; + const char *s; + + if ((s = has_leading_keyword (line, "SOURCE"))) + { + if (!parm->source) + { + parm->source = xtrystrdup (s); + if (!parm->source) + err = gpg_error_from_syserror (); + } + } + + return err; +} + + + /* Data callback for the KS_SEARCH command. */ static gpg_error_t ks_search_data_cb (void *opaque, const void *data, size_t datalen) @@ -248,6 +279,22 @@ ks_search_data_cb (void *opaque, const void *data, size_t datalen) if (parm->lasterr) return 0; + if (parm->stparm->source) + { + err = parm->data_cb (parm->data_cb_value, 1, parm->stparm->source); + if (err) + { + parm->lasterr = err; + return err; + } + /* Clear it so that we won't get back here unless the server + accidentally sends a second source status line. Note that + will not see all accidentally sent source lines because it + depends on whether data lines have been send in between. */ + xfree (parm->stparm->source); + parm->stparm->source = NULL; + } + if (!data) return 0; /* Ignore END commands. */ @@ -270,7 +317,7 @@ ks_search_data_cb (void *opaque, const void *data, size_t datalen) fixedbuf[linelen] = 0; if (linelen && fixedbuf[linelen-1] == '\r') fixedbuf[linelen-1] = 0; - err = parm->data_cb (parm->data_cb_value, fixedbuf); + err = parm->data_cb (parm->data_cb_value, 0, fixedbuf); } else { @@ -289,7 +336,7 @@ ks_search_data_cb (void *opaque, const void *data, size_t datalen) parm->helpbuf[linelen] = 0; if (linelen && parm->helpbuf[linelen-1] == '\r') parm->helpbuf[linelen-1] = 0; - err = parm->data_cb (parm->data_cb_value, parm->helpbuf); + err = parm->data_cb (parm->data_cb_value, 0, parm->helpbuf); } if (err) parm->lasterr = err; @@ -306,17 +353,18 @@ ks_search_data_cb (void *opaque, const void *data, size_t datalen) /* Run the KS_SEARCH command using the search string SEARCHSTR. All data lines are passed to the CB function. That function is called - with CB_VALUE as its first argument and the decoded data line as - second argument. The callback function may modify the data line - and it is guaranteed that this data line is a complete line with a - terminating 0 character but without the linefeed. NULL is passed - to the callback to indicate EOF. */ + with CB_VALUE as its first argument, a 0 as second argument, and + the decoded data line as third argument. The callback function may + modify the data line and it is guaranteed that this data line is a + complete line with a terminating 0 character but without the + linefeed. NULL is passed to the callback to indicate EOF. */ gpg_error_t gpg_dirmngr_ks_search (ctrl_t ctrl, const char *searchstr, - gpg_error_t (*cb)(void*, char *), void *cb_value) + gpg_error_t (*cb)(void*, int, char *), void *cb_value) { gpg_error_t err; assuan_context_t ctx; + struct ks_status_parm_s stparm; struct ks_search_parm_s parm; char line[ASSUAN_LINELENGTH]; @@ -336,18 +384,21 @@ gpg_dirmngr_ks_search (ctrl_t ctrl, const char *searchstr, xfree (escsearchstr); } + memset (&stparm, 0, sizeof stparm); memset (&parm, 0, sizeof parm); init_membuf (&parm.saveddata, 1024); parm.data_cb = cb; parm.data_cb_value = cb_value; + parm.stparm = &stparm; err = assuan_transact (ctx, line, ks_search_data_cb, &parm, - NULL, NULL, NULL, NULL); + NULL, NULL, ks_status_cb, &stparm); if (!err) - err = cb (cb_value, NULL); /* Send EOF. */ + err = cb (cb_value, 0, NULL); /* Send EOF. */ xfree (get_membuf (&parm.saveddata, NULL)); xfree (parm.helpbuf); + xfree (stparm.source); close_context (ctrl, ctx); return err; @@ -382,24 +433,32 @@ ks_get_data_cb (void *opaque, const void *data, size_t datalen) don't need to escape the patterns before sending them to the server. + If R_SOURCE is not NULL the source of the data is stored as a + malloced string there. If a source is not known NULL is stored. + If there are too many patterns the function returns an error. That could be fixed by issuing several search commands or by implementing a different interface. However with long keyids we are able to ask for (1000-10-1)/(2+8+1) = 90 keys at once. */ gpg_error_t -gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern, estream_t *r_fp) +gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern, + estream_t *r_fp, char **r_source) { gpg_error_t err; assuan_context_t ctx; + struct ks_status_parm_s stparm; struct ks_get_parm_s parm; char *line = NULL; size_t linelen; membuf_t mb; int idx; + memset (&stparm, 0, sizeof stparm); memset (&parm, 0, sizeof parm); *r_fp = NULL; + if (r_source) + *r_source = NULL; err = open_context (ctrl, &ctx); if (err) @@ -433,7 +492,7 @@ gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern, estream_t *r_fp) goto leave; } err = assuan_transact (ctx, line, ks_get_data_cb, &parm, - NULL, NULL, NULL, NULL); + NULL, NULL, ks_status_cb, &stparm); if (err) goto leave; @@ -441,8 +500,15 @@ gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern, estream_t *r_fp) *r_fp = parm.memfp; parm.memfp = NULL; + if (r_source) + { + *r_source = stparm.source; + stparm.source = NULL; + } + leave: es_fclose (parm.memfp); + xfree (stparm.source); xfree (line); close_context (ctrl, ctx); return err; diff --git a/g10/call-dirmngr.h b/g10/call-dirmngr.h index 933303d..481b948 100644 --- a/g10/call-dirmngr.h +++ b/g10/call-dirmngr.h @@ -22,9 +22,10 @@ void gpg_dirmngr_deinit_session_data (ctrl_t ctrl); gpg_error_t gpg_dirmngr_ks_search (ctrl_t ctrl, const char *searchstr, - gpg_error_t (*cb)(void*, char *), + gpg_error_t (*cb)(void*, int, char *), void *cb_value); -gpg_error_t gpg_dirmngr_ks_get (ctrl_t ctrl, char *pattern[], estream_t *r_fp); +gpg_error_t gpg_dirmngr_ks_get (ctrl_t ctrl, char *pattern[], + estream_t *r_fp, char **r_source); gpg_error_t gpg_dirmngr_ks_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp); gpg_error_t gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen, diff --git a/g10/keyserver.c b/g10/keyserver.c index b8ab81e..3a3bc40 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -831,17 +831,29 @@ show_prompt (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int numdesc, /* This is a callback used by call-dirmngr.c to process the result of - KS_SEARCH command. LINE is the actual data line received with all - escaping removed and guaranteed to be exactly one line with - stripped LF; an EOF is indicated by LINE passed as NULL. LINE may - be modified after return. */ + KS_SEARCH command. If SPECIAL is 0, LINE is the actual data line + received with all escaping removed and guaranteed to be exactly one + line with stripped LF; an EOF is indicated by LINE passed as NULL. + If special is 1, the line conatins the source of the information + (usually an URL). LINE may be modified after return. */ static gpg_error_t -search_line_handler (void *opaque, char *line) +search_line_handler (void *opaque, int special, char *line) { struct search_line_handler_parm_s *parm = opaque; gpg_error_t err = 0; struct keyrec *keyrec; + if (special == 1) + { + log_info ("data source: %s\n", line); + return 0; + } + else if (special) + { + log_debug ("unknown value %d for special search callback", special); + return 0; + } + if (parm->eof_seen && line) { log_debug ("ooops: unexpected data after EOF\n"); @@ -1478,6 +1490,7 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, char **pattern; int idx, npat; estream_t datastream; + char *source = NULL; /* Create an array filled with a search pattern for each key. The array is delimited by a NULL entry. */ @@ -1561,10 +1574,13 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, } - err = gpg_dirmngr_ks_get (ctrl, pattern, &datastream); + err = gpg_dirmngr_ks_get (ctrl, pattern, &datastream, &source); for (idx=0; idx < npat; idx++) xfree (pattern[idx]); xfree (pattern); + if (opt.verbose) + log_info ("data source: %s\n", source); + if (!err) { void *stats_handle; @@ -1590,7 +1606,7 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, import_release_stats_handle (stats_handle); } es_fclose (datastream); - + xfree (source); return err; } commit 5d321eb00be0774418de1a05678ac0ec44d7193b Author: Werner Koch Date: Wed Mar 12 19:33:30 2014 +0100 dirmngr: Default to a user socket name and enable autostart. * common/homedir.c (dirmngr_socket_name): Rename to dirmngr_sys_socket_name. (dirmngr_user_socket_name): New. * common/asshelp.c (start_new_dirmngr): Handle sys and user dirmngr socket. * dirmngr/dirmngr.c (main): Ditto. * dirmngr/server.c (cmd_getinfo): Ditto. * sm/server.c (gpgsm_server): Ditto. * dirmngr/dirmngr-client.c (start_dirmngr): Likewise. * tools/gpgconf.c (main): Print "dirmngr-sys-socket" with --list-dirs. * configure.ac (USE_DIRMNGR_AUTO_START): Set by default. diff --git a/common/asshelp.c b/common/asshelp.c index b5dde5a..4763de1 100644 --- a/common/asshelp.c +++ b/common/asshelp.c @@ -600,19 +600,41 @@ start_new_dirmngr (assuan_context_t *r_ctx, return err; } - sockname = dirmngr_socket_name (); + sockname = dirmngr_user_socket_name (); + if (sockname) + { + /* First try the local socket name and only if that fails try + the system socket. */ + err = assuan_socket_connect (ctx, sockname, 0, 0); + if (err) + sockname = dirmngr_sys_socket_name (); + } + else + sockname = dirmngr_sys_socket_name (); + err = assuan_socket_connect (ctx, sockname, 0, 0); + #ifdef USE_DIRMNGR_AUTO_START if (err) { lock_spawn_t lock; - const char *argv[2]; + const char *argv[4]; + int try_system_daemon = 0; + char *abs_homedir; + + /* No connection: Try start a new Dirmngr. On Windows this will + fail because the Dirmngr is expected to be a system service. + However on WinCE we don't distinguish users and thus we can + start it. */ + + /* We prefer to start it as a user daemon. */ + sockname = dirmngr_user_socket_name (); + if (!sockname) + { + sockname = dirmngr_sys_socket_name (); + try_system_daemon = 1; + } - /* With no success try start a new Dirmngr. On most systems - this will fail because the Dirmngr is expected to be a system - service. However on Wince we don't distinguish users and - thus we can start it. A future extension might be to use the - userv system to start the Dirmngr as a system service. */ if (!dirmngr_program || !*dirmngr_program) dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR); @@ -624,6 +646,8 @@ start_new_dirmngr (assuan_context_t *r_ctx, status_cb (status_cb_arg, STATUS_PROGRESS, "starting_dirmngr ? 0 0", NULL); + abs_homedir = make_filename (homedir, NULL); + if (fflush (NULL)) { gpg_error_t tmperr = gpg_err_make (errsource, @@ -635,12 +659,25 @@ start_new_dirmngr (assuan_context_t *r_ctx, } argv[0] = "--daemon"; - argv[1] = NULL; + if (try_system_daemon) + argv[1] = NULL; + else + { /* Try starting as user daemon - dirmngr does this if the + home directory is given on the command line. */ + argv[1] = "--homedir"; + argv[2] = abs_homedir; + argv[3] = NULL; + } + + /* On the use of HOMEDIR for locking: Under Windows HOMEDIR is + not used thus it does not matter. Under Unix we should + TRY_SYSTEM_DAEMON should never be true because + dirmngr_user_socket_name() won't return NULL. */ if (!(err = lock_spawning (&lock, homedir, "dirmngr", verbose)) && assuan_socket_connect (ctx, sockname, 0, 0)) { - err = gnupg_spawn_process_detached (dirmngr_program, argv,NULL); + err = gnupg_spawn_process_detached (dirmngr_program, argv, NULL); if (err) log_error ("failed to start the dirmngr '%s': %s\n", dirmngr_program, gpg_strerror (err)); @@ -671,6 +708,7 @@ start_new_dirmngr (assuan_context_t *r_ctx, } unlock_spawning (&lock, "dirmngr"); + xfree (abs_homedir); } #else (void)homedir; diff --git a/common/homedir.c b/common/homedir.c index 77622a1..e2a117b 100644 --- a/common/homedir.c +++ b/common/homedir.c @@ -555,9 +555,9 @@ gnupg_cachedir (void) } -/* Return the default socket name used by DirMngr. */ +/* Return the system socket name used by DirMngr. */ const char * -dirmngr_socket_name (void) +dirmngr_sys_socket_name (void) { #ifdef HAVE_W32_SYSTEM static char *name; @@ -600,6 +600,22 @@ dirmngr_socket_name (void) } +/* Return the user socket name used by DirMngr. If a a user specific + dirmngr installation is not supported, NULL is returned. */ +const char * +dirmngr_user_socket_name (void) +{ +#ifdef HAVE_W32_SYSTEM + return NULL; /* We support only a system service. */ +#else /*!HAVE_W32_SYSTEM*/ + static char *name; + + if (!name) + name = make_filename (default_homedir (), DIRMNGR_SOCK_NAME, NULL); + return name; +#endif /*!HAVE_W32_SYSTEM*/ +} + /* Return the file name of a helper tool. WHICH is one of the GNUPG_MODULE_NAME_foo constants. */ diff --git a/common/util.h b/common/util.h index c4acb0b..4b3cbfc 100644 --- a/common/util.h +++ b/common/util.h @@ -231,7 +231,8 @@ const char *gnupg_libdir (void); const char *gnupg_datadir (void); const char *gnupg_localedir (void); const char *gnupg_cachedir (void); -const char *dirmngr_socket_name (void); +const char *dirmngr_sys_socket_name (void); +const char *dirmngr_user_socket_name (void); /* All module names. We also include gpg and gpgsm for the sake for gpgconf. */ diff --git a/configure.ac b/configure.ac index c20984a..e384fba 100644 --- a/configure.ac +++ b/configure.ac @@ -92,7 +92,7 @@ disable_keyserver_path=no card_support=yes use_ccid_driver=yes use_standard_socket=yes -dirmngr_auto_start=no +dirmngr_auto_start=yes try_ks_ldap=no @@ -428,15 +428,10 @@ AC_ARG_ENABLE(ccid-driver, use_ccid_driver=$enableval) AC_MSG_RESULT($use_ccid_driver) -# -# Dirmngr is nowadays a system service and thus it usually does no -# make sense to start it as needed. However on some systems this is -# possible; this option enable the feature. -# AC_MSG_CHECKING([whether to auto start dirmngr]) AC_ARG_ENABLE(dirmngr-auto-start, - AC_HELP_STRING([--enable-dirmngr-auto-start], - [enable auto starting of the dirmngr]), + AC_HELP_STRING([--disable-dirmngr-auto-start], + [disable auto starting of the dirmngr]), dirmngr_auto_start=$enableval) AC_MSG_RESULT($dirmngr_auto_start) if test "$dirmngr_auto_start" = yes ; then diff --git a/dirmngr/dirmngr-client.c b/dirmngr/dirmngr-client.c index da97443..0e62764 100644 --- a/dirmngr/dirmngr-client.c +++ b/dirmngr/dirmngr-client.c @@ -443,7 +443,10 @@ start_dirmngr (int only_daemon) infostr = opt.force_pipe_server? NULL : getenv (DIRMNGR_INFO_NAME); if (only_daemon && (!infostr || !*infostr)) { - infostr = xstrdup (dirmngr_socket_name ()); + if (dirmngr_user_socket_name ()) + infostr = xstrdup (dirmngr_user_socket_name ()); + else + infostr = xstrdup (dirmngr_sys_socket_name ()); try_default = 1; } diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index 7bcff7a..e3f98c0 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -666,7 +666,6 @@ main (int argc, char **argv) opt.ldaptimeout = DEFAULT_LDAP_TIMEOUT; /* Other defaults. */ - socket_name = dirmngr_socket_name (); /* Check whether we have a config file given on the commandline */ orig_argc = argc; @@ -721,7 +720,12 @@ main (int argc, char **argv) #endif opt.homedir_data = gnupg_datadir (); opt.homedir_cache = gnupg_cachedir (); + socket_name = dirmngr_sys_socket_name (); } + else if (dirmngr_user_socket_name ()) + socket_name = dirmngr_user_socket_name (); + else + socket_name = dirmngr_sys_socket_name (); if (default_config) configname = make_filename (opt.homedir, DIRMNGR_NAME".conf", NULL ); diff --git a/dirmngr/server.c b/dirmngr/server.c index a1d2033..f1319ad 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -1781,7 +1781,10 @@ cmd_getinfo (assuan_context_t ctx, char *line) } else if (!strcmp (line, "socket_name")) { - const char *s = dirmngr_socket_name (); + const char *s = dirmngr_user_socket_name (); + + if (!s) + s = dirmngr_sys_socket_name (); if (s) err = assuan_send_data (ctx, s, strlen (s)); diff --git a/sm/server.c b/sm/server.c index 74caf6c..201a34b 100644 --- a/sm/server.c +++ b/sm/server.c @@ -1296,6 +1296,7 @@ gpgsm_server (certlist_t default_recplist) char *tmp = NULL; const char *s1 = getenv (GPG_AGENT_INFO_NAME); + /* Fixme: Use the really used socket name. */ if (asprintf (&tmp, "Home: %s\n" "Config: %s\n" @@ -1305,7 +1306,9 @@ gpgsm_server (certlist_t default_recplist) opt.homedir, opt.config_filename, s1?s1:"[not set]", - dirmngr_socket_name (), + (dirmngr_user_socket_name () + ? dirmngr_user_socket_name () + : dirmngr_sys_socket_name ()), hello) > 0) { assuan_set_hello_line (ctx, tmp); diff --git a/tools/gpgconf.c b/tools/gpgconf.c index a9bf491..fbce6d3 100644 --- a/tools/gpgconf.c +++ b/tools/gpgconf.c @@ -347,8 +347,20 @@ main (int argc, char **argv) gc_percent_escape (gnupg_datadir ())); es_fprintf (outfp, "localedir:%s\n", gc_percent_escape (gnupg_localedir ())); - es_fprintf (outfp, "dirmngr-socket:%s\n", - gc_percent_escape (dirmngr_socket_name ())); + + if (dirmngr_user_socket_name ()) + { + es_fprintf (outfp, "dirmngr-socket:%s\n", + gc_percent_escape (dirmngr_user_socket_name ())); + es_fprintf (outfp, "dirmngr-sys-socket:%s\n", + gc_percent_escape (dirmngr_sys_socket_name ())); + } + else + { + es_fprintf (outfp, "dirmngr-socket:%s\n", + gc_percent_escape (dirmngr_sys_socket_name ())); + } + { char *infostr = getenv (GPG_AGENT_INFO_NAME); commit 6dd5d99a61f24aff862ccba9f7410d7f1af87c05 Author: Werner Koch Date: Wed Mar 12 18:24:52 2014 +0100 gpg: Add option --dirmngr-program. * g10/gpg.c: Add option --dirmngr-program. * g10/options.h (struct opt): Add field dirmngr_program. * g10/call-dirmngr.c (create_context): Use new var. * dirmngr/dirmngr.c: Include gc-opt-flags.h. (main): Remove GC_OPT_FLAG_*. * tools/gpgconf-comp.c (GC_OPT_FLAG_NO_CHANGE): Move macro to ... * common/gc-opt-flags.h: here. diff --git a/common/gc-opt-flags.h b/common/gc-opt-flags.h index b777c06..11ecec0 100644 --- a/common/gc-opt-flags.h +++ b/common/gc-opt-flags.h @@ -36,5 +36,11 @@ a default, which is described by the value of the ARGDEF field. */ #define GC_OPT_FLAG_NO_ARG_DESC (1UL << 6) +/* The NO_CHANGE flag for an option indicates that the user should not + be allowed to change this option using the standard gpgconf method. + Frontends using gpgconf should grey out such options, so that only + the current value is displayed. */ +#define GC_OPT_FLAG_NO_CHANGE (1UL <<7) + #endif /*GNUPG_GC_OPT_FLAGS_H*/ diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index 0cbdc7b..7bcff7a 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -57,6 +57,7 @@ #include "asshelp.h" #include "ldap-wrapper.h" #include "../common/init.h" +#include "gc-opt-flags.h" /* The plain Windows version uses the windows service system. For example to start the service you may use "sc start dirmngr". @@ -709,7 +710,7 @@ main (int argc, char **argv) } /* If --daemon has been given on the command line but not --homedir, - we switch to /etc/dirmngr as default home directory. Note, that + we switch to /etc/gnupg as default home directory. Note, that this also overrides the GNUPGHOME environment variable. */ if (opt.system_daemon && !homedir_seen) { @@ -910,7 +911,7 @@ main (int argc, char **argv) if (cmd == aServer) { - /* Note that this server mode is maily useful for debugging. */ + /* Note that this server mode is mainly useful for debugging. */ if (argc) wrong_args ("--server"); @@ -1193,23 +1194,6 @@ main (int argc, char **argv) char *filename; char *filename_esc; - /* List options and default values in the GPG Conf format. */ - -/* The following list is taken from gnupg/tools/gpgconf-comp.c. */ -/* Option flags. YOU MUST NOT CHANGE THE NUMBERS OF THE EXISTING - FLAGS, AS THEY ARE PART OF THE EXTERNAL INTERFACE. */ -#define GC_OPT_FLAG_NONE 0UL -/* The DEFAULT flag for an option indicates that the option has a - default value. */ -#define GC_OPT_FLAG_DEFAULT (1UL << 4) -/* The DEF_DESC flag for an option indicates that the option has a - default, which is described by the value of the default field. */ -#define GC_OPT_FLAG_DEF_DESC (1UL << 5) -/* The NO_ARG_DESC flag for an option indicates that the argument has - a default, which is described by the value of the ARGDEF field. */ -#define GC_OPT_FLAG_NO_ARG_DESC (1UL << 6) -#define GC_OPT_FLAG_NO_CHANGE (1UL <<7) - #ifdef HAVE_W32_SYSTEM /* On Windows systems, dirmngr always runs as system daemon, and the per-user configuration is never used. So we short-cut diff --git a/doc/gpg.texi b/doc/gpg.texi index c1ce07b..e1ad33c 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1696,6 +1696,25 @@ been given. Given that this option is not anymore used by @command{gpg2}, it should be avoided if possible. @end ifset + + at ifclear gpgone + at item --agent-program @var{file} + at opindex agent-program +Specify an agent program to be used for secret key operations. The +default value is the @file{/usr/bin/gpg-agent}. This is only used +as a fallback when the environment variable @code{GPG_AGENT_INFO} is not +set or a running agent cannot be connected. + at end ifclear + + at ifset gpgtwoone + at item --dirmngr-program @var{file} + at opindex dirmngr-program +Specify a dirmngr program to be used for keyserver access. The +default value is @file{/usr/sbin/dirmngr}. This is only used as a +fallback when the environment variable @code{DIRMNGR_INFO} is not set or +a running dirmngr cannot be connected. + at end ifset + @item --lock-once @opindex lock-once Lock the databases the first time a lock is requested diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index f7cedaf..3d2594f 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -350,7 +350,7 @@ as a fallback when the environment variable @code{GPG_AGENT_INFO} is not set or a running agent cannot be connected. @item --dirmngr-program @var{file} - at opindex dirmnr-program + at opindex dirmngr-program Specify a dirmngr program to be used for @acronym{CRL} checks. The default value is @file{/usr/sbin/dirmngr}. This is only used as a fallback when the environment variable @code{DIRMNGR_INFO} is not set or diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c index 2310d8b..9935333 100644 --- a/g10/call-dirmngr.c +++ b/g10/call-dirmngr.c @@ -121,7 +121,7 @@ create_context (ctrl_t ctrl, assuan_context_t *r_ctx) err = start_new_dirmngr (&ctx, GPG_ERR_SOURCE_DEFAULT, opt.homedir, - NULL, + opt.dirmngr_program, opt.verbose, DBG_ASSUAN, NULL /*gpg_status2*/, ctrl); if (!err) diff --git a/g10/gpg.c b/g10/gpg.c index d24cc23..361a25a 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -346,6 +346,7 @@ enum cmd_and_opt_values oPersonalDigestPreferences, oPersonalCompressPreferences, oAgentProgram, + oDirmngrProgram, oDisplay, oTTYname, oTTYtype, @@ -739,7 +740,9 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-prefs", "@"), ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-prefs", "@"), ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-prefs", "@"), + ARGPARSE_s_s (oAgentProgram, "agent-program", "@"), + ARGPARSE_s_s (oDirmngrProgram, "dirmngr-program", "@"), ARGPARSE_s_s (oDisplay, "display", "@"), ARGPARSE_s_s (oTTYname, "ttyname", "@"), ARGPARSE_s_s (oTTYtype, "ttytype", "@"), @@ -2974,6 +2977,7 @@ main (int argc, char **argv) pers_compress_list=pargs.r.ret_str; break; case oAgentProgram: opt.agent_program = pargs.r.ret_str; break; + case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break; case oDisplay: set_opt_session_env ("DISPLAY", pargs.r.ret_str); diff --git a/g10/options.h b/g10/options.h index 47b8bfb..592e066 100644 --- a/g10/options.h +++ b/g10/options.h @@ -101,6 +101,7 @@ struct int max_cert_depth; const char *homedir; const char *agent_program; + const char *dirmngr_program; /* Options to be passed to the gpg-agent */ session_env_t session_env; diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index 6d366af..356b251 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -357,11 +357,6 @@ static struct several times. A comma separated list of arguments is used as the argument value. */ #define GC_OPT_FLAG_LIST (1UL << 2) -/* The NO_CHANGE flag for an option indicates that the user should not - be allowed to change this option using the standard gpgconf method. - Frontends using gpgconf should grey out such options, so that only - the current value is displayed. */ -#define GC_OPT_FLAG_NO_CHANGE (1UL <<7) /* A human-readable description for each flag. */ ----------------------------------------------------------------------- Summary of changes: common/asshelp.c | 56 ++++++++++++++++++++++----- common/gc-opt-flags.h | 6 +++ common/homedir.c | 20 +++++++++- common/http.c | 8 +++- common/http.h | 10 +++-- common/stringhelp.c | 2 +- common/util.h | 3 +- configure.ac | 11 ++---- dirmngr/dirmngr-client.c | 5 ++- dirmngr/dirmngr.c | 28 ++++---------- dirmngr/ks-engine-hkp.c | 81 +++++++++++++++++++++++++++------------ dirmngr/server.c | 5 ++- doc/gpg.texi | 19 ++++++++++ doc/gpgsm.texi | 2 +- g10/call-dirmngr.c | 94 +++++++++++++++++++++++++++++++++++++++------- g10/call-dirmngr.h | 5 ++- g10/gpg.c | 4 ++ g10/keyserver.c | 30 +++++++++++---- g10/options.h | 1 + sm/server.c | 5 ++- tools/gpgconf-comp.c | 5 --- tools/gpgconf.c | 16 +++++++- 22 files changed, 312 insertions(+), 104 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Fri Mar 14 19:24:56 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Fri, 14 Mar 2014 19:24:56 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-361-g2223eae Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 2223eaefaf53aa7217ac593b83e4294148a4db5d (commit) from 59b4fb5f4927908af06bb80ecd86adbf6e54ba14 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 2223eaefaf53aa7217ac593b83e4294148a4db5d Author: Werner Koch Date: Fri Mar 14 19:25:58 2014 +0100 gpg-connect-agent: Make it easier to connect to the dirmngr. * tools/gpg-connect-agent.c: Add options --dirmngr and --dirmngr-program. diff --git a/doc/tools.texi b/doc/tools.texi index be1233b..734d619 100644 --- a/doc/tools.texi +++ b/doc/tools.texi @@ -1190,6 +1190,18 @@ Try to be as quiet as possible. @opindex agent-program Specify the agent program to be started if none is running. + at ifset gpgtwoone + at item --dirmngr-program @var{file} + at opindex dirmngr-program +Specify the directory manager (keyserver client) program to be started +if none is running. This has only an effect if used together with the +option @option{--dirmngr}. + + at item --dirmngr + at opindex dirmngr +Connect to a running directory manager (keyserver client) instead of +to the gpg-agent. If a dirmngr is not running, start it. + at end ifset @item -S @itemx --raw-socket @var{name} diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c index 6288a97..42e315c 100644 --- a/tools/gpg-connect-agent.c +++ b/tools/gpg-connect-agent.c @@ -1,5 +1,6 @@ /* gpg-connect-agent.c - Tool to connect to the agent. * Copyright (C) 2005, 2007, 2008, 2010 Free Software Foundation, Inc. + * Copyright (C) 2014 Werner Koch * * This file is part of GnuPG. * @@ -58,9 +59,11 @@ enum cmd_and_opt_values oNoVerbose = 500, oHomedir, oAgentProgram, + oDirmngrProgram, oHex, oDecode, - oNoExtConnect + oNoExtConnect, + oDirmngr }; @@ -73,6 +76,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oQuiet, "quiet", N_("quiet")), ARGPARSE_s_n (oHex, "hex", N_("print data out hex encoded")), ARGPARSE_s_n (oDecode,"decode", N_("decode received data lines")), + ARGPARSE_s_n (oDirmngr,"dirmngr", N_("connect to the dirmngr")), ARGPARSE_s_s (oRawSocket, "raw-socket", N_("|NAME|connect to Assuan socket NAME")), ARGPARSE_s_s (oTcpSocket, "tcp-socket", @@ -88,6 +92,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oNoVerbose, "no-verbose", "@"), ARGPARSE_s_s (oHomedir, "homedir", "@" ), ARGPARSE_s_s (oAgentProgram, "agent-program", "@"), + ARGPARSE_s_s (oDirmngrProgram, "dirmngr-program", "@"), ARGPARSE_end () }; @@ -100,8 +105,10 @@ struct int quiet; /* Be extra quiet. */ const char *homedir; /* Configuration directory name */ const char *agent_program; /* Value of --agent-program. */ + const char *dirmngr_program; /* Value of --dirmngr-program. */ int hex; /* Print data lines in hex format. */ int decode; /* Decode received data lines. */ + int use_dirmngr; /* Use the dirmngr and not gpg-agent. */ const char *raw_socket; /* Name of socket to connect in raw mode. */ const char *tcp_socket; /* Name of server to connect in tcp mode. */ int exec; /* Run the pgm given on the command line. */ @@ -1207,8 +1214,10 @@ main (int argc, char **argv) case oNoVerbose: opt.verbose = 0; break; case oHomedir: opt.homedir = pargs.r.ret_str; break; case oAgentProgram: opt.agent_program = pargs.r.ret_str; break; + case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break; case oHex: opt.hex = 1; break; case oDecode: opt.decode = 1; break; + case oDirmngr: opt.use_dirmngr = 1; break; case oRawSocket: opt.raw_socket = pargs.r.ret_str; break; case oTcpSocket: opt.tcp_socket = pargs.r.ret_str; break; case oExec: opt.exec = 1; break; @@ -2202,15 +2211,22 @@ start_agent (void) if (!session_env) log_fatal ("error allocating session environment block: %s\n", strerror (errno)); - - err = start_new_gpg_agent (&ctx, + if (opt.use_dirmngr) + err = start_new_dirmngr (&ctx, GPG_ERR_SOURCE_DEFAULT, opt.homedir, - opt.agent_program, - NULL, NULL, - session_env, + opt.dirmngr_program, !opt.quiet, 0, NULL, NULL); + else + err = start_new_gpg_agent (&ctx, + GPG_ERR_SOURCE_DEFAULT, + opt.homedir, + opt.agent_program, + NULL, NULL, + session_env, + !opt.quiet, 0, + NULL, NULL); session_env_release (session_env); if (err) ----------------------------------------------------------------------- Summary of changes: doc/tools.texi | 12 ++++++++++++ tools/gpg-connect-agent.c | 28 ++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 6 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Mon Mar 17 15:39:03 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Mon, 17 Mar 2014 15:39:03 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-363-g1e2e39c Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 1e2e39c5758ffaf62f8bb85b4a86dc49c41f3a68 (commit) via 1d642d3ca890daa65ee5dd949a00747da6b49015 (commit) from 2223eaefaf53aa7217ac593b83e4294148a4db5d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 1e2e39c5758ffaf62f8bb85b4a86dc49c41f3a68 Author: Werner Koch Date: Mon Mar 17 15:39:33 2014 +0100 gpg: Make --auto-key-locate work again with keyservers. * dirmngr/ks-engine-hkp.c (ks_hkp_get): Allow exact search mode. * g10/keyserver.c (keyserver_import_name): Implement. (keyserver_get): Use exact mode for name based import. (keyserver_get): Add args R_FPR and R_FPRLEN. Change all callers. diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 7b67302..e485e62 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -1040,7 +1040,9 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) { gpg_error_t err; KEYDB_SEARCH_DESC desc; - char kidbuf[40+1]; + char kidbuf[2+40+1]; + const char *exactname = NULL; + char *searchkey = NULL; char *hostport = NULL; char *request = NULL; estream_t fp = NULL; @@ -1060,16 +1062,22 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) switch (desc.mode) { case KEYDB_SEARCH_MODE_SHORT_KID: - snprintf (kidbuf, sizeof kidbuf, "%08lX", (ulong)desc.u.kid[1]); + snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]); break; case KEYDB_SEARCH_MODE_LONG_KID: - snprintf (kidbuf, sizeof kidbuf, "%08lX%08lX", + snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX", (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]); break; case KEYDB_SEARCH_MODE_FPR20: case KEYDB_SEARCH_MODE_FPR: /* This is a v4 fingerprint. */ - bin2hex (desc.u.fpr, 20, kidbuf); + kidbuf[0] = '0'; + kidbuf[1] = 'x'; + bin2hex (desc.u.fpr, 20, kidbuf+2); + break; + + case KEYDB_SEARCH_MODE_EXACT: + exactname = desc.u.name; break; case KEYDB_SEARCH_MODE_FPR16: @@ -1078,6 +1086,14 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) return gpg_error (GPG_ERR_INV_USER_ID); } + searchkey = http_escape_string (exactname? exactname : kidbuf, + EXTRA_ESCAPE_CHARS); + if (!searchkey) + { + err = gpg_error_from_syserror (); + goto leave; + } + reselect = 0; again: /* Build the request string. */ @@ -1092,8 +1108,9 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) xfree (request); request = strconcat (hostport, - "/pks/lookup?op=get&options=mr&search=0x", - kidbuf, + "/pks/lookup?op=get&options=mr&search=", + searchkey, + exactname? "&exact=on":"", NULL); if (!request) { @@ -1123,6 +1140,7 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) es_fclose (fp); xfree (request); xfree (hostport); + xfree (searchkey); return err; } diff --git a/dirmngr/server.c b/dirmngr/server.c index f1319ad..bdfb755 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -1603,7 +1603,8 @@ static const char hlp_ks_get[] = "KS_GET {}\n" "\n" "Get the keys matching PATTERN from the configured OpenPGP keyservers\n" - "(see command KEYSERVER). Each pattern should be a keyid or a fingerprint"; + "(see command KEYSERVER). Each pattern should be a keyid, a fingerprint,\n" + "or an exact name indicastes by the '=' prefix."; static gpg_error_t cmd_ks_get (assuan_context_t ctx, char *line) { diff --git a/g10/keyserver.c b/g10/keyserver.c index 3a3bc40..ac70da9 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -1,6 +1,7 @@ /* keyserver.c - generic keyserver code * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2011, 2012 Free Software Foundation, Inc. + * Copyright (C) 2014 Werner Koch * * This file is part of GnuPG. * @@ -110,7 +111,8 @@ static struct parse_options keyserver_opts[]= static gpg_error_t keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, - struct keyserver_spec *keyserver); + struct keyserver_spec *keyserver, + unsigned char **r_fpr, size_t *r_fprlen); static gpg_error_t keyserver_put (ctrl_t ctrl, strlist_t keyspecs, struct keyserver_spec *keyserver); @@ -819,7 +821,7 @@ show_prompt (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int numdesc, } for (idx = 0; idx < numidx; idx++) selarray[idx] = desc[numarray[idx]-1]; - err = keyserver_get (ctrl, selarray, numidx, NULL); + err = keyserver_get (ctrl, selarray, numidx, NULL, NULL, NULL); xfree (selarray); } } @@ -1039,6 +1041,7 @@ keyserver_export (ctrl_t ctrl, strlist_t users) return rc; } + int keyserver_import (ctrl_t ctrl, strlist_t users) { @@ -1071,13 +1074,31 @@ keyserver_import (ctrl_t ctrl, strlist_t users) } if(count>0) - rc=keyserver_get (ctrl, desc, count, NULL); + rc=keyserver_get (ctrl, desc, count, NULL, NULL, NULL); xfree(desc); return rc; } + +/* Import all keys that exactly match NAME */ +int +keyserver_import_name (ctrl_t ctrl, const char *name, + unsigned char **fpr, size_t *fprlen, + struct keyserver_spec *keyserver) +{ + KEYDB_SEARCH_DESC desc; + + memset (&desc, 0, sizeof desc); + + desc.mode = KEYDB_SEARCH_MODE_EXACT; + desc.u.name = name; + + return keyserver_get (ctrl, &desc, 1, keyserver, fpr, fprlen); +} + + int keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len, struct keyserver_spec *keyserver) @@ -1097,7 +1118,7 @@ keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len, /* TODO: Warn here if the fingerprint we got doesn't match the one we asked for? */ - return keyserver_get (ctrl, &desc, 1, keyserver); + return keyserver_get (ctrl, &desc, 1, keyserver, NULL, NULL); } int @@ -1112,7 +1133,7 @@ keyserver_import_keyid (ctrl_t ctrl, desc.u.kid[0]=keyid[0]; desc.u.kid[1]=keyid[1]; - return keyserver_get (ctrl, &desc,1, keyserver); + return keyserver_get (ctrl, &desc,1, keyserver, NULL, NULL); } /* code mostly stolen from do_export_stream */ @@ -1316,7 +1337,7 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users) /* We use the keyserver structure we parsed out before. Note that a preferred keyserver without a scheme:// will be interpreted as hkp:// */ - rc = keyserver_get (ctrl, &desc[i], 1, keyserver); + rc = keyserver_get (ctrl, &desc[i], 1, keyserver, NULL, NULL); if(rc) log_info(_("WARNING: unable to refresh key %s" " via %s: %s\n"),keystr_from_desc(&desc[i]), @@ -1346,7 +1367,7 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users) count,opt.keyserver->uri); } - rc=keyserver_get (ctrl, desc, numdesc, NULL); + rc=keyserver_get (ctrl, desc, numdesc, NULL, NULL, NULL); } xfree(desc); @@ -1469,21 +1490,15 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens) -/* Called using: - -import_name: - rc = keyserver_work (ctrl, KS_GETNAME, list, NULL, - 0, fpr, fpr_len, keyserver); - -import_ldap: - rc = keyserver_work (ctrl, KS_GETNAME, list, NULL, - 0, fpr, fpr_len, keyserver); - - */ - +/* Retrieve a key from a keyserver. The search pattern are in + (DESC,NDESC). Allowed search modes are keyid, fingerprint, and + exact searches. KEYSERVER gives an optional override keyserver. If + (R_FPR,R_FPRLEN) are not NULL, the may retrun the fingerprint of + one imported key. */ static gpg_error_t keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, - struct keyserver_spec *keyserver) + struct keyserver_spec *keyserver, + unsigned char **r_fpr, size_t *r_fprlen) { gpg_error_t err = 0; @@ -1536,10 +1551,12 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, } else if(desc[idx].mode == KEYDB_SEARCH_MODE_EXACT) { - /* FIXME: We don't need this. It is used as a dummy by - keyserver_fetch which passes an entire URL. Better use a - separate function here. */ - pattern[npat] = xtrystrdup ("0x0000000000000000"); + /* The Dirmngr uses also classify_user_id to detect the type + of the search string. By adding the '=' prefix we force + Dirmngr's KS_GET to consider this an exact search string. + (In gpg 1.4 and gpg 2.0 the keyserver helpers used the + KS_GETNAME command to indicate this.) */ + pattern[npat] = strconcat ("=", desc[idx].u.name, NULL); if (!pattern[npat]) err = gpg_error_from_syserror (); else @@ -1578,7 +1595,7 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, for (idx=0; idx < npat; idx++) xfree (pattern[idx]); xfree (pattern); - if (opt.verbose) + if (opt.verbose && source) log_info ("data source: %s\n", source); if (!err) @@ -1599,7 +1616,8 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, never accept or send them but we better protect against rogue keyservers. */ - import_keys_es_stream (ctrl, datastream, stats_handle, NULL, NULL, + import_keys_es_stream (ctrl, datastream, stats_handle, + r_fpr, r_fprlen, (opt.keyserver_options.import_options | IMPORT_NO_SECKEY)); import_print_stats (stats_handle); @@ -1824,31 +1842,18 @@ keyserver_import_pka (ctrl_t ctrl, return rc; } -/* Import all keys that match name */ -int -keyserver_import_name (ctrl_t ctrl, const char *name, - unsigned char **fpr, size_t *fpr_len, - struct keyserver_spec *keyserver) -{ - strlist_t list=NULL; - int rc; - - append_to_strlist(&list,name); - - rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED); /* FIXME */ - /* keyserver_work (ctrl, KS_GETNAME, list, NULL, */ - /* 0, fpr, fpr_len, keyserver); */ - - free_strlist(list); - - return rc; -} /* Import a key by name using LDAP */ int keyserver_import_ldap (ctrl_t ctrl, - const char *name,unsigned char **fpr,size_t *fpr_len) + const char *name, unsigned char **fpr, size_t *fprlen) { + (void)ctrl; + (void)name; + (void)fpr; + (void)fprlen; + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); /*FIXME*/ +#if 0 char *domain; struct keyserver_spec *keyserver; strlist_t list=NULL; @@ -1919,4 +1924,5 @@ keyserver_import_ldap (ctrl_t ctrl, free_keyserver_spec(keyserver); return rc; +#endif } commit 1d642d3ca890daa65ee5dd949a00747da6b49015 Author: Werner Koch Date: Mon Mar 17 15:36:15 2014 +0100 gpg: New mechanism "clear" for --auto-key-locate. * g10/getkey.c (parse_auto_key_locate): Implement "clear". diff --git a/doc/gpg.texi b/doc/gpg.texi index e1ad33c..b926a8a 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1482,6 +1482,10 @@ mechanisms, in the order they are to be tried: position of this mechanism in the list does not matter. It is not required if @code{local} is also used. + @item clear + Clear all defined mechanisms. This is usefule to override + mechanisms fiven in a config file. + @end table @item --keyid-format @code{short|0xshort|long|0xlong} diff --git a/g10/getkey.c b/g10/getkey.c index 9cad71b..777f383 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -712,7 +712,7 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk, is_mbox = is_valid_mailbox (name); - /* Check whether we the default local search has been disabled. + /* Check whether the default local search has been disabled. This is the case if either the "nodefault" or the "local" keyword are in the list of auto key locate mechanisms. @@ -2809,7 +2809,14 @@ parse_auto_key_locate (char *options) akl = xmalloc_clear (sizeof (*akl)); - if (ascii_strcasecmp (tok, "nodefault") == 0) + if (ascii_strcasecmp (tok, "clear") == 0) + { + xfree (akl); + free_akl (opt.auto_key_locate); + opt.auto_key_locate = NULL; + continue; + } + else if (ascii_strcasecmp (tok, "nodefault") == 0) akl->type = AKL_NODEFAULT; else if (ascii_strcasecmp (tok, "local") == 0) akl->type = AKL_LOCAL; ----------------------------------------------------------------------- Summary of changes: dirmngr/ks-engine-hkp.c | 30 ++++++++++++--- dirmngr/server.c | 3 +- doc/gpg.texi | 4 ++ g10/getkey.c | 11 +++++- g10/keyserver.c | 98 +++++++++++++++++++++++++---------------------- 5 files changed, 91 insertions(+), 55 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Mon Mar 17 18:14:07 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Mon, 17 Mar 2014 18:14:07 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-364-gf90cfe6 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via f90cfe6b66269de0154d810c5cee1fe9a5af475c (commit) from 1e2e39c5758ffaf62f8bb85b4a86dc49c41f3a68 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit f90cfe6b66269de0154d810c5cee1fe9a5af475c Author: Werner Koch Date: Mon Mar 17 17:54:36 2014 +0100 gpg: Reject signatures made with MD5. * g10/gpg.c: Add option --allow-weak-digest-algos. (main): Set option also in PGP2 mode. * g10/options.h (struct opt): Add flags.allow_weak_digest_algos. * g10/sig-check.c (do_check): Reject MD5 signatures. * tests/openpgp/defs.inc: Add allow_weak_digest_algos to gpg.conf. diff --git a/doc/gpg.texi b/doc/gpg.texi index b926a8a..91186f2 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -2276,9 +2276,10 @@ a message that PGP 2.x will not be able to handle. Note that `PGP available, but the MIT release is a good common baseline. This option implies @option{--rfc1991 --disable-mdc ---no-force-v4-certs --escape-from-lines --force-v3-sigs --cipher-algo -IDEA --digest-algo MD5 --compress-algo ZIP}. It also disables - at option{--textmode} when encrypting. +--no-force-v4-certs --escape-from-lines --force-v3-sigs +--allow-weak-digest-algos --cipher-algo IDEA --digest-algo +MD5--compress-algo ZIP}. It also disables @option{--textmode} when +encrypting. @item --pgp6 @opindex pgp6 @@ -2734,6 +2735,13 @@ necessary to get as much data as possible out of the corrupt message. However, be aware that a MDC protection failure may also mean that the message was tampered with intentionally by an attacker. + at item --allow-weak-digest-algos + at opindex allow-weak-digest-algos +Signatures made with the broken MD5 algorithm are normally rejected +with an ``invalid digest algorithm'' message. This option allows the +verification of signatures made with such weak algorithms. + + @item --no-default-keyring @opindex no-default-keyring Do not add the default keyrings to the list of keyrings. Note that diff --git a/g10/gpg.c b/g10/gpg.c index 361a25a..7529e81 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -374,6 +374,7 @@ enum cmd_and_opt_values oDisableDSA2, oAllowMultipleMessages, oNoAllowMultipleMessages, + oAllowWeakDigestAlgos, oFakedSystemTime, oNoop @@ -768,6 +769,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oDisableDSA2, "disable-dsa2", "@"), ARGPARSE_s_n (oAllowMultipleMessages, "allow-multiple-messages", "@"), ARGPARSE_s_n (oNoAllowMultipleMessages, "no-allow-multiple-messages", "@"), + ARGPARSE_s_n (oAllowWeakDigestAlgos, "allow-weak-digest-algos", "@"), /* These two are aliases to help users of the PGP command line product use gpg with minimal pain. Many commands are common @@ -3066,6 +3068,10 @@ main (int argc, char **argv) opt.flags.allow_multiple_messages=0; break; + case oAllowWeakDigestAlgos: + opt.flags.allow_weak_digest_algos = 1; + break; + case oFakedSystemTime: { time_t faked_time = isotime2epoch (pargs.r.ret_str); @@ -3280,6 +3286,7 @@ main (int argc, char **argv) opt.pgp2_workarounds = 1; opt.ask_sig_expire = 0; opt.ask_cert_expire = 0; + opt.flags.allow_weak_digest_algos = 1; xfree(def_digest_string); def_digest_string = xstrdup("md5"); xfree(s2k_digest_string); diff --git a/g10/options.h b/g10/options.h index 592e066..c622a46 100644 --- a/g10/options.h +++ b/g10/options.h @@ -228,6 +228,7 @@ struct unsigned int utf8_filename:1; unsigned int dsa2:1; unsigned int allow_multiple_messages:1; + unsigned int allow_weak_digest_algos:1; } flags; /* Linked list of ways to find a key if the key isn't on the local diff --git a/g10/sig-check.c b/g10/sig-check.c index a307533..0cbb7f2 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -266,6 +266,22 @@ do_check( PKT_public_key *pk, PKT_signature *sig, gcry_md_hd_t digest, if( (rc=do_check_messages(pk,sig,r_expired,r_revoked)) ) return rc; + if (sig->digest_algo == GCRY_MD_MD5 + && !opt.flags.allow_weak_digest_algos) + { + static int shown; + + if (!shown) + { + log_info + (_("Note: signatures using the %s algorithm are rejected\n"), + "MD5"); + shown = 1; + } + + return GPG_ERR_DIGEST_ALGO; + } + /* Make sure the digest algo is enabled (in case of a detached signature). */ gcry_md_enable (digest, sig->digest_algo); diff --git a/tests/openpgp/defs.inc b/tests/openpgp/defs.inc index 008d32a..2faa4c2 100755 --- a/tests/openpgp/defs.inc +++ b/tests/openpgp/defs.inc @@ -245,6 +245,7 @@ for f in gpg.conf gpg-agent.conf ; do gpg.conf) [ -n "${opt_always}" ] && echo "no-auto-check-trustdb" >>"$f" echo "agent-program $GPG_AGENT" >>"$f" + echo "allow-weak-digest-algos" >>"$f" ;; gpg-agent.conf) ----------------------------------------------------------------------- Summary of changes: doc/gpg.texi | 14 +++++++++++--- g10/gpg.c | 7 +++++++ g10/options.h | 1 + g10/sig-check.c | 16 ++++++++++++++++ tests/openpgp/defs.inc | 1 + 5 files changed, 36 insertions(+), 3 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Tue Mar 18 11:06:02 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Tue, 18 Mar 2014 11:06:02 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-366-g6c058fa Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 6c058fac65c7e9d1ffb72686f0f02644f172da22 (commit) via 04e304278c9302831bc81e7fe9049c588ead029a (commit) from f90cfe6b66269de0154d810c5cee1fe9a5af475c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6c058fac65c7e9d1ffb72686f0f02644f172da22 Author: Werner Koch Date: Tue Mar 18 11:07:05 2014 +0100 dirmngr: Resurrect hosts in the HKP hosttable. * dirmngr/dirmngr.c (HOUSEKEEPING_INTERVAL): New. (housekeeping_thread): New. (handle_tick): Call new function. * dirmngr/ks-engine-hkp.c (RESURRECT_INTERVAL): New. (struct hostinfo_s): Add field died_at and set it along with the dead flag. (ks_hkp_print_hosttable): Print that info. (ks_hkp_housekeeping): New. -- The resurrection gives the host a chance to get back to life the next time a new host is selected. diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index e3f98c0..ab65720 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -1,23 +1,22 @@ /* dirmngr.c - LDAP access - * Copyright (C) 2002 Klar?lvdalens Datakonsult AB - * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2010, 2011 g10 Code GmbH + * Copyright (C) 2002 Klar?lvdalens Datakonsult AB + * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2010, 2011 g10 Code GmbH + * Copyright (C) 2014 Werner Koch * - * This file is part of DirMngr. + * This file is part of GnuPG. * - * DirMngr is free software; you can redistribute it and/or modify + * 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 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * - * DirMngr is distributed in the hope that it will be useful, + * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + * along with this program; if not, see . */ #include @@ -243,9 +242,7 @@ static int active_connections; /* The timer tick used for housekeeping stuff. For Windows we use a longer period as the SetWaitableTimer seems to signal earlier than - the 2 seconds. CHECK_OWN_SOCKET_INTERVAL defines how often we - check our own socket in standard socket mode. If that value is 0 - we don't check at all. All values are in seconds. */ + the 2 seconds. All values are in seconds. */ #if defined(HAVE_W32CE_SYSTEM) # define TIMERTICK_INTERVAL (60) #elif defined(HAVE_W32_SYSTEM) @@ -254,6 +251,9 @@ static int active_connections; # define TIMERTICK_INTERVAL (2) #endif +#define HOUSEKEEPING_INTERVAL (600) + + /* This union is used to avoid compiler warnings in case a pointer is 64 bit and an int 32 bit. We store an integer in a pointer and get it back later (npth_getspecific et al.). */ @@ -1657,14 +1657,49 @@ handle_signal (int signo) #endif /*!HAVE_W32_SYSTEM*/ +/* Thread to do the housekeeping. */ +static void * +housekeeping_thread (void *arg) +{ + static int sentinel; + time_t curtime; + + (void)arg; + + curtime = gnupg_get_time (); + if (sentinel) + { + log_info ("housekeeping is already going on\n"); + return NULL; + } + sentinel++; + if (opt.verbose) + log_info ("starting housekeeping\n"); + + ks_hkp_housekeeping (curtime); + + if (opt.verbose) + log_info ("ready with housekeeping\n"); + sentinel--; + return NULL; + +} + + /* This is the worker for the ticker. It is called every few seconds and may only do fast operations. */ static void handle_tick (void) { - /* Nothing real to do right now. Actually we need the timeout only - for W32 where we don't use signals and need a way for the loop to - check for the shutdown flag. */ + static time_t last_housekeeping; + time_t curtime; + + curtime = gnupg_get_time (); + if (!last_housekeeping) + last_housekeeping = curtime; + + /* Under Windows we don't use signals and need a way for the loop to + check for the shutdown flag. */ #ifdef HAVE_W32_SYSTEM if (shutdown_pending) log_info (_("SIGTERM received - shutting down ...\n")); @@ -1676,6 +1711,30 @@ handle_tick (void) dirmngr_exit (0); } #endif /*HAVE_W32_SYSTEM*/ + + /* Start a housekeeping thread every 10 minutes */ + if (last_housekeeping + HOUSEKEEPING_INTERVAL <= curtime + || last_housekeeping > curtime /*(be prepared for y2038)*/) + { + npth_t thread; + npth_attr_t tattr; + int err; + + last_housekeeping = curtime; + + err = npth_attr_init (&tattr); + if (err) + log_error ("error preparing housekeeping thread: %s\n", strerror (err)); + else + { + npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED); + err = npth_create (&thread, &tattr, housekeeping_thread, NULL); + if (err) + log_error ("error spawning housekeeping thread: %s\n", + strerror (err)); + npth_attr_destroy (&tattr); + } + } } diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h index 4f5cbd1..bb368f2 100644 --- a/dirmngr/dirmngr.h +++ b/dirmngr/dirmngr.h @@ -1,15 +1,16 @@ /* dirmngr.h - Common definitions for the dirmngr - * Copyright (C) 2002 Klar?lvdalens Datakonsult AB - * Copyright (C) 2004 g10 Code GmbH + * Copyright (C) 2002 Klar?lvdalens Datakonsult AB + * Copyright (C) 2004 g10 Code GmbH + * Copyright (C) 2014 Werner Koch * - * This file is part of DirMngr. + * This file is part of GnuPG. * - * DirMngr is free software; you can redistribute it and/or modify + * 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 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * - * DirMngr is distributed in the hope that it will be useful, + * 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. @@ -183,6 +184,11 @@ void dirmngr_exit( int ); /* Wrapper for exit() */ void dirmngr_init_default_ctrl (ctrl_t ctrl); void dirmngr_sighup_action (void); + +/*-- Various housekeeping functions. --*/ +void ks_hkp_housekeeping (time_t curtime); + + /*-- server.c --*/ ldap_server_t get_ldapservers_from_ctrl (ctrl_t ctrl); ksba_cert_t get_cert_local (ctrl_t ctrl, const char *issuer); @@ -196,4 +202,5 @@ gpg_error_t dirmngr_status_help (ctrl_t ctrl, const char *text); gpg_error_t dirmngr_tick (ctrl_t ctrl); + #endif /*DIRMNGR_H*/ diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index e485e62..fa616a0 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -46,6 +46,9 @@ #endif +/* Number of seconds after a host is marked as resurrected. */ +#define RESURRECT_INTERVAL (3600*3) /* 3 hours */ + /* To match the behaviour of our old gpgkeys helper code we escape more characters than actually needed. */ #define EXTRA_ESCAPE_CHARS "@!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~" @@ -70,6 +73,8 @@ struct hostinfo_s unsigned int v4:1; /* Host supports AF_INET. */ unsigned int v6:1; /* Host supports AF_INET6. */ unsigned int dead:1; /* Host is currently unresponsive. */ + time_t died_at; /* The time the host was marked dead. IF this is + 0 the host has been manually marked dead. */ char name[1]; /* The hostname. */ }; @@ -104,6 +109,7 @@ create_new_hostinfo (const char *name) hi->v4 = 0; hi->v6 = 0; hi->dead = 0; + hi->died_at = 0; /* Add it to the hosttable. */ for (idx=0; idx < hosttable_size; idx++) @@ -465,6 +471,9 @@ mark_host_dead (const char *name) log_info ("marking host '%s' as dead%s\n", hi->name, hi->dead? " (again)":""); hi->dead = 1; + hi->died_at = gnupg_get_time (); + if (!hi->died_at) + hi->died_at = 1; done = 1; } } @@ -500,6 +509,7 @@ ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive) else if (!alive && !hi->dead) { hi->dead = 1; + hi->died_at = 0; /* Manually set dead. */ err = ks_printf_help (ctrl, "marking '%s' as dead", name); } @@ -538,6 +548,7 @@ ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive) else if (!alive && !hi2->dead) { hi2->dead = 1; + hi2->died_at = 0; /* Manually set dead. */ err = ks_printf_help (ctrl, "marking '%s' as dead", hi2->name); } @@ -556,18 +567,33 @@ ks_hkp_print_hosttable (ctrl_t ctrl) int idx, idx2; hostinfo_t hi; membuf_t mb; - char *p; + time_t curtime; + char *p, *died; + const char *diedstr; - err = ks_print_help (ctrl, "hosttable (idx, ipv4, ipv6, dead, name):"); + err = ks_print_help (ctrl, "hosttable (idx, ipv4, ipv6, dead, name, time):"); if (err) return err; + curtime = gnupg_get_time (); for (idx=0; idx < hosttable_size; idx++) if ((hi=hosttable[idx])) { - err = ks_printf_help (ctrl, "%3d %s %s %s %s\n", + if (hi->dead && hi->died_at) + { + died = elapsed_time_string (hi->died_at, curtime); + diedstr = died? died : "error"; + } + else + diedstr = died = NULL; + err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s\n", idx, hi->v4? "4":" ", hi->v6? "6":" ", - hi->dead? "d":" ", hi->name); + hi->dead? "d":" ", hi->name, + diedstr? " (":"", + diedstr? diedstr:"", + diedstr? ")":"" ); + xfree (died); + if (err) return err; if (hi->pool) @@ -682,6 +708,34 @@ ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri) } +/* Housekeeping function called from the housekeeping thread. It is + used to mark dead hosts alive so that they may be tried again after + some time. */ +void +ks_hkp_housekeeping (time_t curtime) +{ + int idx; + hostinfo_t hi; + + for (idx=0; idx < hosttable_size; idx++) + { + hi = hosttable[idx]; + if (!hi) + continue; + if (!hi->dead) + continue; + if (!hi->died_at) + continue; /* Do not resurrect manually shot hosts. */ + if (hi->died_at + RESURRECT_INTERVAL <= curtime + || hi->died_at > curtime) + { + hi->dead = 0; + log_info ("resurrected host '%s'", hi->name); + } + } +} + + /* Send an HTTP request. On success returns an estream object at R_FP. HOSTPORTSTR is only used for diagnostics. If POST_CB is not NULL a post request is used and that callback is called to allow commit 04e304278c9302831bc81e7fe9049c588ead029a Author: Werner Koch Date: Tue Mar 18 11:02:50 2014 +0100 common: New function elapsed_time_string. * common/gettime.c (elapsed_time_string): New. diff --git a/common/gettime.c b/common/gettime.c index 6bdf3c5..788743f 100644 --- a/common/gettime.c +++ b/common/gettime.c @@ -430,6 +430,45 @@ strtimevalue( u32 value ) } + +/* Return a malloced string with the time elapsed between NOW and + SINCE. May return NULL on error. */ +char * +elapsed_time_string (time_t since, time_t now) +{ + char *result; + double diff; + unsigned long value; + unsigned int days, hours, minutes, seconds; + + if (!now) + now = gnupg_get_time (); + + diff = difftime (now, since); + if (diff < 0) + return xtrystrdup ("time-warp"); + + seconds = (unsigned long)diff % 60; + value = (unsigned long)(diff / 60); + minutes = value % 60; + value /= 60; + hours = value % 24; + value /= 24; + days = value % 365; + + if (days) + result = xtryasprintf ("%ud%uh%um%us", days, hours, minutes, seconds); + else if (hours) + result = xtryasprintf ("%uh%um%us", hours, minutes, seconds); + else if (minutes) + result = xtryasprintf ("%um%us", minutes, seconds); + else + result = xtryasprintf ("%us", seconds); + + return result; +} + + /* * Note: this function returns GMT */ diff --git a/common/gettime.h b/common/gettime.h index bc914ad..736eb41 100644 --- a/common/gettime.h +++ b/common/gettime.h @@ -33,6 +33,8 @@ void gnupg_get_isotime (gnupg_isotime_t timebuf); void gnupg_set_time (time_t newtime, int freeze); int gnupg_faked_time_p (void); u32 make_timestamp (void); +char *elapsed_time_string (time_t since, time_t now); + u32 scan_isodatestr (const char *string); int isotime_p (const char *string); int isotime_human_p (const char *string); ----------------------------------------------------------------------- Summary of changes: common/gettime.c | 39 +++++++++++++++++++++ common/gettime.h | 2 ++ dirmngr/dirmngr.c | 89 +++++++++++++++++++++++++++++++++++++++-------- dirmngr/dirmngr.h | 19 ++++++---- dirmngr/ks-engine-hkp.c | 62 ++++++++++++++++++++++++++++++--- 5 files changed, 186 insertions(+), 25 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Wed Mar 19 16:42:43 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Wed, 19 Mar 2014 16:42:43 +0100 Subject: [git] ADNS-g10 - branch, master, updated. adns-1.4-g10-3-2-g859ca67 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "ADNS migrated to autotools/libtool". The branch, master has been updated via 859ca67cbff1c6d7e850e53d99a9e57c93021b16 (commit) from 0e63141f80e5eba46b6bb2a29cd1b93fdcdff8f7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 859ca67cbff1c6d7e850e53d99a9e57c93021b16 Author: Werner Koch Date: Wed Mar 19 16:35:52 2014 +0100 adnslogres: Support IPv6 and improve privacy mode. * client/adnslogres.c: Add assert.h. (TRUNCIPLEN): New. (OPT_VHOST): New. (expand_v6): New. (ipaddr2domain): Rewrite. (printline): Print truncated IP if resolving failed and append 4 or 6 to indicate the used protocol. (readline): Request raw ptr vor v6. Handle new parameters. (main): Add option -x. diff --git a/client/adnslogres.c b/client/adnslogres.c index 1e07f12..cd3ac23 100644 --- a/client/adnslogres.c +++ b/client/adnslogres.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "config.h" #include "adns.h" @@ -60,10 +61,15 @@ /* maximum length of a line */ #define MAXLINE 2048 +/* Max length of a truncated IP string. + "nnnn:nnnn:n000::" or "nnn.nnn.0.0" */ +#define TRUNCIPLEN 16 + /* option flags */ #define OPT_DEBUG 1 #define OPT_POLL 2 #define OPT_PRIVACY 4 +#define OPT_VHOST 8 static const char *const progname= "adnslogres"; static const char *config_text; @@ -488,43 +494,195 @@ rmd160_hash_buffer (void *outbuf, const void *buffer, size_t length) } +/* Expand an IPv6 address string by inserting missing '0', changing + letters to lowercase, and removing the the colons. Returns a + pointer to a static buffer or NULL on error. Example: + "2001:aA8:fff1:2100::60" gives + "20010aa8fff121000000000000000060". */ +static char * +expand_v6 (const char *addrstr) +{ + static char buffer[32+1]; + char tmpbuf[4]; + int tmpidx, idx, i; + const char *s; + int ncolon; + + for (s=addrstr, ncolon=0; *s && !sensible_ctype (isspace, *s); s++) + { + if (*s == ':') + ncolon++; + } + if (ncolon > 8) + return NULL; /* Oops. */ + + memset (buffer, '0', 32); + buffer[32] = 0; + idx = tmpidx = 0; + for (s=addrstr; *s && !sensible_ctype (isspace, *s); s++) + { + if (*s == ':') + { + idx += 4 - tmpidx; + for (i=0; i < tmpidx; i++) + { + if (idx >= sizeof buffer) + return NULL; + buffer[idx++] = tmpbuf[i]; + } + tmpidx = 0; + if (s[1] == ':') /* Double colon. */ + { + s++; + if (!ncolon || s[1] == ':') + return NULL; /* More than one double colon. */ + idx += 4*(8 - ncolon); + ncolon = 0; + } + } + else if (tmpidx > 3) + return NULL; /* Invalid address. */ + else if (!sensible_ctype (isxdigit, *s)) + return NULL; /* Invalid character. */ + else + tmpbuf[tmpidx++] = sensible_ctype (tolower, *s); + } + + idx += 4 - tmpidx; + for (i=0; i < tmpidx; i++) + { + if (idx >= sizeof buffer) + return NULL; + buffer[idx++] = tmpbuf[i]; + } + + return buffer; +} + + /* - * Parse the IP address and convert to a reverse domain name. + * Parse the IP address and convert to a reverse domain name. ON + * return a truncated IP address is stored at TRUNCIP which is + * expected to be a buffer of at least TRUNCIPLEN+1 bytes. */ -static char *ipaddr2domain(char *start, char **addr, char **rest) { - static char buf[30]; /* "123.123.123.123.in-addr.arpa.\0" */ - char *ptrs[5]; +static char * +ipaddr2domain(char *start, char **addr, char **rest, char *truncip, + int *r_is_v6, int opts) +{ + /* Sample values BUF needs to hold: + * "123.123.123.123.in-addr.arpa." + * "0.6.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.2.1.f.f.f.8.a.a.0.1.0.0.2.ip6.arpa." + */ + static char buf[74]; int i; + char *endp; + int ndots = 0; - ptrs[0]= start; -retry: - while (!sensible_ctype(isdigit,*ptrs[0])) - if (!*ptrs[0]++) { - strcpy(buf, "invalid."); - *addr= *rest= NULL; - return buf; + *r_is_v6 = 0; + + /* Better skip leading spaces which might have been create by some + log processing scripts. */ + while (sensible_ctype(isspace, *start)) + start++; + + if ((opts & OPT_VHOST)) + { + while (!sensible_ctype(isspace, *start)) + start++; + while (sensible_ctype(isspace, *start)) + start++; } - for (i= 1; i < 5; i++) { - ptrs[i]= ptrs[i-1]; - while (sensible_ctype(isdigit,*ptrs[i]++)); - if ((i == 4 && !sensible_ctype(isspace,ptrs[i][-1])) || - (i != 4 && ptrs[i][-1] != '.') || - (ptrs[i]-ptrs[i-1] > 4)) { - ptrs[0]= ptrs[i]-1; - goto retry; + + for (endp = start; !sensible_ctype(isspace, *endp); endp++) + { + if (*endp == ':') + *r_is_v6 = 1; + else if (*endp == '.') + ndots++; } - } - sprintf(buf, "%.*s.%.*s.%.*s.%.*s.in-addr.arpa.", - (int)(ptrs[4]-ptrs[3]-1), ptrs[3], - (int)(ptrs[3]-ptrs[2]-1), ptrs[2], - (int)(ptrs[2]-ptrs[1]-1), ptrs[1], - (int)(ptrs[1]-ptrs[0]-1), ptrs[0]); - *addr= ptrs[0]; - *rest= ptrs[4]-1; + if (endp == start) + { + strcpy (buf, "invalid"); + *addr = *rest = NULL; + goto leave; + } + + if (*r_is_v6) + { + const char *exp = expand_v6 (start); + const char *s; + char *p; + size_t len; + + if (!exp) + { + strcpy (buf, "invalid_v6"); + *addr = *rest = NULL; + goto leave; + } + + len = strlen (exp); + assert (len + 9 + 1 <= sizeof buf); + p = buf; + for (s = exp + len - 1; s >= exp; s--) + { + *p++ = *s; + *p++ = '.'; + } + strcpy (p, "ip6.arpa."); + snprintf (truncip, TRUNCIPLEN+1, "%.4s:%.4s:%.1s000::", + exp, exp+4, exp+8); + *addr = start; + *rest = endp; + } + else /* v4 */ + { + char *ptrs[5]; + + /* Largest expected string is "255.255.255.255". */ + if ((endp - start) > 15 || ndots != 3) + { + strcpy (buf, "invalid_v4"); + *addr = *rest = NULL; + goto leave; + } + ptrs[0] = start; + for (i = 1; i < 5; i++) + { + ptrs[i] = ptrs[i-1]; + while (sensible_ctype (isdigit, *ptrs[i]++)) + ; + if ((i == 4 && !sensible_ctype (isspace, ptrs[i][-1])) + || (i != 4 && ptrs[i][-1] != '.') + || (ptrs[i]-ptrs[i-1] > 4) + || (i!=4 && !sensible_ctype (isdigit, ptrs[i][0]))) + { + strcpy (buf, "invalid_v4"); + *addr = *rest = NULL; + goto leave; + } + } + + snprintf (buf, sizeof buf, "%.*s.%.*s.%.*s.%.*s.in-addr.arpa.", + (int)(ptrs[4]-ptrs[3]-1), ptrs[3], + (int)(ptrs[3]-ptrs[2]-1), ptrs[2], + (int)(ptrs[2]-ptrs[1]-1), ptrs[1], + (int)(ptrs[1]-ptrs[0]-1), ptrs[0]); + snprintf (truncip, TRUNCIPLEN+1, "%.*s.%.*s.0.0", + (int)(ptrs[1]-ptrs[0]-1), ptrs[0], + (int)(ptrs[2]-ptrs[1]-1), ptrs[1]); + *addr= ptrs[0]; + *rest= ptrs[4]-1; + } + + leave: return buf; } -static void printline(FILE *outf, char *start, char *addr, char *rest, char *domain, int opts) { +static void +printline(FILE *outf, char *start, char *addr, char *rest, char *domain, + const char *truncip, int is_v6, int opts) +{ if (domain) { char *p; @@ -539,11 +697,13 @@ static void printline(FILE *outf, char *start, char *addr, char *rest, char *dom fprintf(outf, "%.*sp", (int)(addr - start), start); for (i=0; i < 4; i++) fprintf (outf, "%02x", hash[i]); - fprintf(outf, "%s%s", p, rest); + fprintf(outf, "%c%s%s", is_v6? '6':'4', p, rest); } else fprintf(outf, "%.*s%s%s", (int)(addr - start), start, domain, rest); } + else if ((opts & OPT_PRIVACY)) + fprintf(outf, "%.*s%s%s", (int)(addr - start), start, truncip, rest); else fputs(start, outf); if (ferror(outf)) aargh("write output"); @@ -552,6 +712,8 @@ static void printline(FILE *outf, char *start, char *addr, char *rest, char *dom typedef struct logline { struct logline *next; char *start, *addr, *rest; + char truncip[TRUNCIPLEN+1]; + int is_v6; adns_query query; } logline; @@ -566,11 +728,16 @@ static logline *readline(FILE *inf, adns_state adns, int opts) { line= (logline*)str; line->next= NULL; line->start= str+sizeof(logline); + line->is_v6 = 0; + *line->truncip = 0; strcpy(line->start, buf); - str= ipaddr2domain(line->start, &line->addr, &line->rest); + str= ipaddr2domain(line->start, &line->addr, &line->rest, line->truncip, + &line->is_v6, opts); if (opts & OPT_DEBUG) msg("submitting %.*s -> %s", (int)(line->rest-line->addr), guard_null(line->addr), str); - if (adns_submit(adns, str, adns_r_ptr, + /* Note: ADNS does not yet support "ptr" for IPv6. */ + if (adns_submit(adns, str, + line->is_v6? adns_r_ptr_raw : adns_r_ptr, adns_qf_quoteok_cname|adns_qf_cname_loose, NULL, &line->query)) aargh("adns_submit"); @@ -616,7 +783,8 @@ static void proclog(FILE *inf, FILE *outf, int maxpending, int opts) { exit(1); } printline(outf, head->start, head->addr, head->rest, - answer->status == adns_s_ok ? *answer->rrs.str : NULL, opts); + answer->status == adns_s_ok ? *answer->rrs.str : NULL, + head->truncip, head->is_v6, opts); line= head; head= head->next; free(line); free(answer); @@ -643,8 +811,13 @@ static void printhelp(FILE *file) { " -p use poll(2) instead of select(2)\n" " -d turn on debugging\n" " -P privacy mode\n" + " -x first field is the virtual host\n" " -S salt for the privacy mode\n" - " -C use instead of contents of resolv.conf\n", + " -C use instead of contents of resolv.conf\n" + "\n" + "The privacy mode replaces resolved addresses by a 32 bit hash value\n" + "or truncates IP addresses to 16/40 bit. A random salt should be\n" + "used to make testing for addresses hard.\n", stdout); } @@ -672,7 +845,7 @@ int main(int argc, char *argv[]) { maxpending= DEFMAXPENDING; opts= 0; - while ((c= getopt(argc, argv, "c:C:dpPS:")) != -1) + while ((c= getopt(argc, argv, "c:C:dxpPS:")) != -1) switch (c) { case 'c': maxpending= atoi(optarg); @@ -687,6 +860,9 @@ int main(int argc, char *argv[]) { case 'd': opts|= OPT_DEBUG; break; + case 'x': + opts|= OPT_VHOST; + break; case 'P': opts|= OPT_PRIVACY; break; ----------------------------------------------------------------------- Summary of changes: client/adnslogres.c | 244 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 210 insertions(+), 34 deletions(-) hooks/post-receive -- ADNS migrated to autotools/libtool http://git.gnupg.org From cvs at cvs.gnupg.org Wed Mar 19 22:48:32 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Wed, 19 Mar 2014 22:48:32 +0100 Subject: [git] ADNS-g10 - branch, master, updated. adns-1.4-g10-3-3-g9296627 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "ADNS migrated to autotools/libtool". The branch, master has been updated via 9296627651b662c0bdf19232187501a03ffd89d9 (commit) from 859ca67cbff1c6d7e850e53d99a9e57c93021b16 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 9296627651b662c0bdf19232187501a03ffd89d9 Author: Werner Koch Date: Wed Mar 19 22:41:52 2014 +0100 adnslogres: Change -P to also map unresolved addresses. diff --git a/client/adnslogres.c b/client/adnslogres.c index cd3ac23..4c6b1a7 100644 --- a/client/adnslogres.c +++ b/client/adnslogres.c @@ -61,9 +61,8 @@ /* maximum length of a line */ #define MAXLINE 2048 -/* Max length of a truncated IP string. - "nnnn:nnnn:n000::" or "nnn.nnn.0.0" */ -#define TRUNCIPLEN 16 +/* Length of a buffer to hold an expanded IP addr string incl 0. */ +#define FULLIPBUFLEN 33 /* option flags */ #define OPT_DEBUG 1 @@ -561,12 +560,12 @@ expand_v6 (const char *addrstr) /* - * Parse the IP address and convert to a reverse domain name. ON - * return a truncated IP address is stored at TRUNCIP which is - * expected to be a buffer of at least TRUNCIPLEN+1 bytes. + * Parse the IP address and convert to a reverse domain name. On + * return the full IP address is stored at FULLIP which is + * expected to be a buffer of at least FULLIPBUFLEN bytes. */ static char * -ipaddr2domain(char *start, char **addr, char **rest, char *truncip, +ipaddr2domain(char *start, char **addr, char **rest, char *fullip, int *r_is_v6, int opts) { /* Sample values BUF needs to hold: @@ -623,6 +622,9 @@ ipaddr2domain(char *start, char **addr, char **rest, char *truncip, len = strlen (exp); assert (len + 9 + 1 <= sizeof buf); + assert (len < FULLIPBUFLEN); + strcpy (fullip, exp); + p = buf; for (s = exp + len - 1; s >= exp; s--) { @@ -630,8 +632,6 @@ ipaddr2domain(char *start, char **addr, char **rest, char *truncip, *p++ = '.'; } strcpy (p, "ip6.arpa."); - snprintf (truncip, TRUNCIPLEN+1, "%.4s:%.4s:%.1s000::", - exp, exp+4, exp+8); *addr = start; *rest = endp; } @@ -646,6 +646,8 @@ ipaddr2domain(char *start, char **addr, char **rest, char *truncip, *addr = *rest = NULL; goto leave; } + snprintf (fullip, FULLIPBUFLEN, "%.*s", (int)(endp-start), start); + ptrs[0] = start; for (i = 1; i < 5; i++) { @@ -668,9 +670,6 @@ ipaddr2domain(char *start, char **addr, char **rest, char *truncip, (int)(ptrs[3]-ptrs[2]-1), ptrs[2], (int)(ptrs[2]-ptrs[1]-1), ptrs[1], (int)(ptrs[1]-ptrs[0]-1), ptrs[0]); - snprintf (truncip, TRUNCIPLEN+1, "%.*s.%.*s.0.0", - (int)(ptrs[1]-ptrs[0]-1), ptrs[0], - (int)(ptrs[2]-ptrs[1]-1), ptrs[1]); *addr= ptrs[0]; *rest= ptrs[4]-1; } @@ -680,21 +679,29 @@ ipaddr2domain(char *start, char **addr, char **rest, char *truncip, } static void -printline(FILE *outf, char *start, char *addr, char *rest, char *domain, - const char *truncip, int is_v6, int opts) +printline(FILE *outf, char *start, char *addr, char *rest, const char *domain, + const char *fullip, int is_v6, int opts) { + int append_null = 0; + + if ((opts & OPT_PRIVACY) && !domain && *fullip) + { + domain = fullip; + append_null = 1; + } + if (domain) { - char *p; + const char *p; - p = strrchr (domain, '.'); + p = append_null? ".null" : strrchr (domain, '.'); if ((opts & OPT_PRIVACY) && p && p[1]) { unsigned char hash[20]; int i; rmd160_hash_buffer (hash, domain, strlen (domain)); - fprintf(outf, "%.*sp", (int)(addr - start), start); + fprintf (outf, "%.*sp", (int)(addr - start), start); for (i=0; i < 4; i++) fprintf (outf, "%02x", hash[i]); fprintf(outf, "%c%s%s", is_v6? '6':'4', p, rest); @@ -702,17 +709,17 @@ printline(FILE *outf, char *start, char *addr, char *rest, char *domain, else fprintf(outf, "%.*s%s%s", (int)(addr - start), start, domain, rest); } - else if ((opts & OPT_PRIVACY)) - fprintf(outf, "%.*s%s%s", (int)(addr - start), start, truncip, rest); else fputs(start, outf); - if (ferror(outf)) aargh("write output"); + + if (ferror(outf)) + aargh("write output"); } typedef struct logline { struct logline *next; char *start, *addr, *rest; - char truncip[TRUNCIPLEN+1]; + char fullip[FULLIPBUFLEN]; int is_v6; adns_query query; } logline; @@ -729,9 +736,9 @@ static logline *readline(FILE *inf, adns_state adns, int opts) { line->next= NULL; line->start= str+sizeof(logline); line->is_v6 = 0; - *line->truncip = 0; + *line->fullip = 0; strcpy(line->start, buf); - str= ipaddr2domain(line->start, &line->addr, &line->rest, line->truncip, + str= ipaddr2domain(line->start, &line->addr, &line->rest, line->fullip, &line->is_v6, opts); if (opts & OPT_DEBUG) msg("submitting %.*s -> %s", (int)(line->rest-line->addr), guard_null(line->addr), str); @@ -784,7 +791,7 @@ static void proclog(FILE *inf, FILE *outf, int maxpending, int opts) { } printline(outf, head->start, head->addr, head->rest, answer->status == adns_s_ok ? *answer->rrs.str : NULL, - head->truncip, head->is_v6, opts); + head->fullip, head->is_v6, opts); line= head; head= head->next; free(line); free(answer); @@ -815,9 +822,8 @@ static void printhelp(FILE *file) { " -S salt for the privacy mode\n" " -C use instead of contents of resolv.conf\n" "\n" - "The privacy mode replaces resolved addresses by a 32 bit hash value\n" - "or truncates IP addresses to 16/40 bit. A random salt should be\n" - "used to make testing for addresses hard.\n", + "The privacy mode replaces addresses by a 32 bit hash value.\n" + "A daily salt should be used to make testing for addresses hard.\n", stdout); } ----------------------------------------------------------------------- Summary of changes: client/adnslogres.c | 60 ++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 27 deletions(-) hooks/post-receive -- ADNS migrated to autotools/libtool http://git.gnupg.org From cvs at cvs.gnupg.org Sat Mar 22 21:13:41 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Sat, 22 Mar 2014 21:13:41 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-369-g0724328 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 072432883ededa15bf35f80102e0572746ba4af1 (commit) via a77ed0f266d03e234027dda4de5a7f3dd6787b1e (commit) via 6376227a31b3076321ce16ad626b333057bda53d (commit) from 6c058fac65c7e9d1ffb72686f0f02644f172da22 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 072432883ededa15bf35f80102e0572746ba4af1 Author: Werner Koch Date: Sat Mar 22 21:12:46 2014 +0100 agent: Support the Ed25519 signature algorithm for ssh. * agent/command-ssh.c (SPEC_FLAG_IS_EdDSA): New. (ssh_key_types): Add entry for ssh-ed25519. (ssh_identifier_from_curve_name): Move to the top. (stream_read_skip): New. (stream_read_blob): New. (ssh_signature_encoder_rsa): Replace MPIS array by an s-exp and move the s-exp parsing to here. (ssh_signature_encoder_dsa): Ditto. (ssh_signature_encoder_ecdsa): Ditto. (ssh_signature_encoder_eddsa): New. (sexp_key_construct): Rewrite. (ssh_key_extract): Rename to ... (ssh_key_to_blob): .. this and rewrite most of it. (ssh_receive_key): Add case for EdDSA. (ssh_convert_key_to_blob, key_secret_to_public): Remove. (ssh_send_key_public): Rewrite. (ssh_handler_request_identities): Simplify. (data_sign): Add rename args. Add new args HASH and HASHLEN. Make use of es_fopenmen and es_fclose_snatch. Remove parsing into MPIs which is now doe in the sgnature encoder functions. (ssh_handler_sign_request): Take care of Ed25519. (ssh_key_extract_comment): Rewrite using gcry_sexp_nth_string. -- To make the code easier readable most of the Ed25591 work has been done using a new explicit code path. Warning: Libgcrypt 1.6.1 uses a non optimized implementation for Ed25519 and timing attacks might be possible. While working on the code I realized that it could need more rework; it is at some places quite baroque and more complicated than needed. Given that we require Libgcrypt 1.6 anyway, we should make more use of modern Libgcrypt functions. diff --git a/agent/command-ssh.c b/agent/command-ssh.c index fb3b29a..be2ab3b 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -1,6 +1,6 @@ /* command-ssh.c - gpg-agent's ssh-agent emulation layer * Copyright (C) 2004, 2005, 2006, 2009, 2012 Free Software Foundation, Inc. - * Copyright (C) 2013 Werner Koch + * Copyright (C) 2013, 2014 Werner Koch * * This file is part of GnuPG. * @@ -74,6 +74,7 @@ #define SSH_DSA_SIGNATURE_ELEMS 2 #define SPEC_FLAG_USE_PKCS1V2 (1 << 0) #define SPEC_FLAG_IS_ECDSA (1 << 1) +#define SPEC_FLAG_IS_EdDSA (1 << 2) /*(lowercase 'd' on purpose.)*/ /* The name of the control file. */ #define SSH_CONTROL_FILE_NAME "sshcontrol" @@ -138,7 +139,7 @@ typedef gpg_error_t (*ssh_key_modifier_t) (const char *elems, functions are necessary. */ typedef gpg_error_t (*ssh_signature_encoder_t) (ssh_key_type_spec_t *spec, estream_t signature_blob, - gcry_mpi_t *mpis); + gcry_sexp_t sig); /* Type, which is used for boundling all the algorithm specific information together in a single object. */ @@ -229,13 +230,17 @@ static gpg_error_t ssh_handler_unlock (ctrl_t ctrl, static gpg_error_t ssh_key_modifier_rsa (const char *elems, gcry_mpi_t *mpis); static gpg_error_t ssh_signature_encoder_rsa (ssh_key_type_spec_t *spec, estream_t signature_blob, - gcry_mpi_t *mpis); + gcry_sexp_t signature); static gpg_error_t ssh_signature_encoder_dsa (ssh_key_type_spec_t *spec, estream_t signature_blob, - gcry_mpi_t *mpis); + gcry_sexp_t signature); static gpg_error_t ssh_signature_encoder_ecdsa (ssh_key_type_spec_t *spec, estream_t signature_blob, - gcry_mpi_t *mpis); + gcry_sexp_t signature); +static gpg_error_t ssh_signature_encoder_eddsa (ssh_key_type_spec_t *spec, + estream_t signature_blob, + gcry_sexp_t signature); +static gpg_error_t ssh_key_extract_comment (gcry_sexp_t key, char **comment); @@ -266,9 +271,14 @@ static ssh_request_spec_t request_specs[] = static ssh_key_type_spec_t ssh_key_types[] = { { + "ssh-ed25519", "ecc", "qd", "q", "rs", "qd", + NULL, ssh_signature_encoder_eddsa, + "Ed25519", 0, SPEC_FLAG_IS_EdDSA + }, + { "ssh-rsa", "rsa", "nedupq", "en", "s", "nedpqu", ssh_key_modifier_rsa, ssh_signature_encoder_rsa, - NULL, 0, SPEC_FLAG_USE_PKCS1V2 + NULL, 0, SPEC_FLAG_USE_PKCS1V2 }, { "ssh-dss", "dsa", "pqgyx", "pqgy", "rs", "pqgyx", @@ -290,7 +300,6 @@ static ssh_key_type_spec_t ssh_key_types[] = NULL, ssh_signature_encoder_ecdsa, "nistp521", GCRY_MD_SHA512, SPEC_FLAG_IS_ECDSA } - }; @@ -336,7 +345,20 @@ make_cstring (const char *data, size_t data_n) return s; } +/* Lookup the ssh-identifier for the ECC curve CURVE_NAME. Returns + NULL if not found. */ +static const char * +ssh_identifier_from_curve_name (const char *curve_name) +{ + int i; + + for (i = 0; i < DIM (ssh_key_types); i++) + if (ssh_key_types[i].curve_name + && !strcmp (ssh_key_types[i].curve_name, curve_name)) + return ssh_key_types[i].ssh_identifier; + return NULL; +} /* @@ -459,6 +481,34 @@ stream_read_data (estream_t stream, unsigned char *buffer, size_t size) return err; } +/* Skip over SIZE bytes from STREAM. */ +static gpg_error_t +stream_read_skip (estream_t stream, size_t size) +{ + char buffer[128]; + size_t bytes_to_read, bytes_read; + int ret; + + do + { + bytes_to_read = size; + if (bytes_to_read > sizeof buffer) + bytes_to_read = sizeof buffer; + + ret = es_read (stream, buffer, bytes_to_read, &bytes_read); + if (ret) + return gpg_error_from_syserror (); + else if (bytes_read != bytes_to_read) + return gpg_error (GPG_ERR_EOF); + else + size -= bytes_to_read; + } + while (size); + + return 0; +} + + /* Write SIZE bytes from BUFFER to STREAM. */ static gpg_error_t stream_write_data (estream_t stream, const unsigned char *buffer, size_t size) @@ -525,21 +575,68 @@ stream_read_string (estream_t stream, unsigned int secure, return err; } -/* Read a C-string from STREAM, store copy in STRING. */ + +/* Read a binary string from STREAM and store it as an opaque MPI at + R_MPI. Depending on SECURE use secure memory. If the string is + too large for key material return an error. */ static gpg_error_t -stream_read_cstring (estream_t stream, char **string) +stream_read_blob (estream_t stream, unsigned int secure, gcry_mpi_t *r_mpi) { - unsigned char *buffer; gpg_error_t err; + unsigned char *buffer = NULL; + u32 length = 0; - err = stream_read_string (stream, 0, &buffer, NULL); + *r_mpi = NULL; + + /* Read string length. */ + err = stream_read_uint32 (stream, &length); if (err) - goto out; + goto leave; + + /* To avoid excessive use of secure memory we check that an MPI is + not too large. */ + if (length > (4096/8) + 8) + { + log_error (_("ssh keys greater than %d bits are not supported\n"), 4096); + err = GPG_ERR_TOO_LARGE; + goto leave; + } - *string = (char *) buffer; + /* Allocate space. */ + if (secure) + buffer = xtrymalloc_secure (length? length:1); + else + buffer = xtrymalloc (length?length:1); + if (!buffer) + { + err = gpg_error_from_syserror (); + goto leave; + } - out: + /* Read data. */ + err = stream_read_data (stream, buffer, length); + if (err) + goto leave; + *r_mpi = gcry_mpi_set_opaque (NULL, buffer, 8*length); + buffer = NULL; + + leave: + xfree (buffer); + return err; +} + + +/* Read a C-string from STREAM, store copy in STRING. */ +static gpg_error_t +stream_read_cstring (estream_t stream, char **string) +{ + gpg_error_t err; + unsigned char *buffer; + + err = stream_read_string (stream, 0, &buffer, NULL); + if (!err) + *string = (char *)buffer; return err; } @@ -635,6 +732,7 @@ stream_write_mpi (estream_t stream, gcry_mpi_t mpint) return err; } + /* Copy data from SRC to DST until EOF is reached. */ static gpg_error_t stream_copy (estream_t dst, estream_t src) @@ -753,7 +851,7 @@ open_control_file (ssh_control_file_t *r_cf, int append) err = gpg_error_from_syserror (); goto leave; } - /* FIXME: With "a+" we are not able to check whether this will will + /* FIXME: With "a+" we are not able to check whether this will be created and thus the blurb needs to be written first. */ cf->fp = fopen (cf->fname, append? "a+":"r"); if (!cf->fp && errno == ENOENT) @@ -1245,15 +1343,63 @@ ssh_key_modifier_rsa (const char *elems, gcry_mpi_t *mpis) /* Signature encoder function for RSA. */ static gpg_error_t ssh_signature_encoder_rsa (ssh_key_type_spec_t *spec, - estream_t signature_blob, gcry_mpi_t *mpis) + estream_t signature_blob, + gcry_sexp_t s_signature) { + gpg_error_t err = 0; + gcry_sexp_t valuelist = NULL; + gcry_sexp_t sublist = NULL; + gcry_mpi_t sig_value = NULL; + gcry_mpi_t *mpis = NULL; + const char *elems; + size_t elems_n; + int i; + unsigned char *data; size_t data_n; - gpg_error_t err; gcry_mpi_t s; - (void)spec; + valuelist = gcry_sexp_nth (s_signature, 1); + if (!valuelist) + { + err = gpg_error (GPG_ERR_INV_SEXP); + goto out; + } + + elems = spec->elems_signature; + elems_n = strlen (elems); + + mpis = xtrycalloc (elems_n + 1, sizeof *mpis); + if (!mpis) + { + err = gpg_error_from_syserror (); + goto out; + } + + for (i = 0; i < elems_n; i++) + { + sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1); + if (!sublist) + { + err = gpg_error (GPG_ERR_INV_SEXP); + break; + } + + sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG); + if (!sig_value) + { + err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */ + break; + } + gcry_sexp_release (sublist); + sublist = NULL; + + mpis[i] = sig_value; + } + if (err) + goto out; + /* RSA specific */ s = mpis[0]; err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &data, &data_n, s); @@ -1264,7 +1410,9 @@ ssh_signature_encoder_rsa (ssh_key_type_spec_t *spec, xfree (data); out: - + gcry_sexp_release (valuelist); + gcry_sexp_release (sublist); + mpint_list_free (mpis); return err; } @@ -1272,17 +1420,63 @@ ssh_signature_encoder_rsa (ssh_key_type_spec_t *spec, /* Signature encoder function for DSA. */ static gpg_error_t ssh_signature_encoder_dsa (ssh_key_type_spec_t *spec, - estream_t signature_blob, gcry_mpi_t *mpis) + estream_t signature_blob, + gcry_sexp_t s_signature) { + gpg_error_t err = 0; + gcry_sexp_t valuelist = NULL; + gcry_sexp_t sublist = NULL; + gcry_mpi_t sig_value = NULL; + gcry_mpi_t *mpis = NULL; + const char *elems; + size_t elems_n; + int i; + unsigned char buffer[SSH_DSA_SIGNATURE_PADDING * SSH_DSA_SIGNATURE_ELEMS]; - unsigned char *data; + unsigned char *data = NULL; size_t data_n; - gpg_error_t err; - int i; - (void)spec; + valuelist = gcry_sexp_nth (s_signature, 1); + if (!valuelist) + { + err = gpg_error (GPG_ERR_INV_SEXP); + goto out; + } + + elems = spec->elems_signature; + elems_n = strlen (elems); + + mpis = xtrycalloc (elems_n + 1, sizeof *mpis); + if (!mpis) + { + err = gpg_error_from_syserror (); + goto out; + } + + for (i = 0; i < elems_n; i++) + { + sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1); + if (!sublist) + { + err = gpg_error (GPG_ERR_INV_SEXP); + break; + } + + sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG); + if (!sig_value) + { + err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */ + break; + } + gcry_sexp_release (sublist); + sublist = NULL; + + mpis[i] = sig_value; + } + if (err) + goto out; - data = NULL; + /* DSA specific code. */ /* FIXME: Why this complicated code? Why collecting boths mpis in a buffer instead of writing them out one after the other? */ @@ -1312,9 +1506,10 @@ ssh_signature_encoder_dsa (ssh_key_type_spec_t *spec, err = stream_write_string (signature_blob, buffer, sizeof (buffer)); out: - xfree (data); - + gcry_sexp_release (valuelist); + gcry_sexp_release (sublist); + mpint_list_free (mpis); return err; } @@ -1322,15 +1517,62 @@ ssh_signature_encoder_dsa (ssh_key_type_spec_t *spec, /* Signature encoder function for ECDSA. */ static gpg_error_t ssh_signature_encoder_ecdsa (ssh_key_type_spec_t *spec, - estream_t stream, gcry_mpi_t *mpis) + estream_t stream, gcry_sexp_t s_signature) { + gpg_error_t err = 0; + gcry_sexp_t valuelist = NULL; + gcry_sexp_t sublist = NULL; + gcry_mpi_t sig_value = NULL; + gcry_mpi_t *mpis = NULL; + const char *elems; + size_t elems_n; + int i; + unsigned char *data[2] = {NULL, NULL}; size_t data_n[2]; size_t innerlen; - gpg_error_t err; - int i; - (void)spec; + valuelist = gcry_sexp_nth (s_signature, 1); + if (!valuelist) + { + err = gpg_error (GPG_ERR_INV_SEXP); + goto out; + } + + elems = spec->elems_signature; + elems_n = strlen (elems); + + mpis = xtrycalloc (elems_n + 1, sizeof *mpis); + if (!mpis) + { + err = gpg_error_from_syserror (); + goto out; + } + + for (i = 0; i < elems_n; i++) + { + sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1); + if (!sublist) + { + err = gpg_error (GPG_ERR_INV_SEXP); + break; + } + + sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG); + if (!sig_value) + { + err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */ + break; + } + gcry_sexp_release (sublist); + sublist = NULL; + + mpis[i] = sig_value; + } + if (err) + goto out; + + /* ECDSA specific */ innerlen = 0; for (i = 0; i < DIM(data); i++) @@ -1355,103 +1597,230 @@ ssh_signature_encoder_ecdsa (ssh_key_type_spec_t *spec, out: for (i = 0; i < DIM(data); i++) xfree (data[i]); + gcry_sexp_release (valuelist); + gcry_sexp_release (sublist); + mpint_list_free (mpis); return err; } -/* - S-Expressions. - */ - - -/* This function constructs a new S-Expression for the key identified - by the KEY_SPEC, SECRET, CURVE_NAME, MPIS, and COMMENT, which is to - be stored at R_SEXP. Returns an error code. */ +/* Signature encoder function for EdDSA. */ static gpg_error_t -sexp_key_construct (gcry_sexp_t *r_sexp, - ssh_key_type_spec_t key_spec, int secret, - const char *curve_name, gcry_mpi_t *mpis, - const char *comment) +ssh_signature_encoder_eddsa (ssh_key_type_spec_t *spec, + estream_t stream, gcry_sexp_t s_signature) { - const char *key_identifier[] = { "public-key", "private-key" }; - gpg_error_t err; - gcry_sexp_t sexp_new = NULL; - void *formatbuf = NULL; - void **arg_list = NULL; - int arg_idx; - estream_t format; + gpg_error_t err = 0; + gcry_sexp_t valuelist = NULL; + gcry_sexp_t sublist = NULL; + gcry_mpi_t sig_value = NULL; + gcry_mpi_t *mpis = NULL; const char *elems; size_t elems_n; - unsigned int i, j; + int i; - if (secret) - elems = key_spec.elems_sexp_order; - else - elems = key_spec.elems_key_public; - elems_n = strlen (elems); + unsigned char *data[2] = {NULL, NULL}; + size_t data_n[2]; + size_t totallen; - format = es_fopenmem (0, "a+b"); - if (!format) + valuelist = gcry_sexp_nth (s_signature, 1); + if (!valuelist) { - err = gpg_error_from_syserror (); + err = gpg_error (GPG_ERR_INV_SEXP); goto out; } - /* Key identifier, algorithm identifier, mpis, comment, and a NULL - as a safeguard. */ - arg_list = xtrymalloc (sizeof (*arg_list) * (2 + 1 + elems_n + 1 + 1)); - if (!arg_list) + elems = spec->elems_signature; + elems_n = strlen (elems); + + mpis = xtrycalloc (elems_n + 1, sizeof *mpis); + if (!mpis) { err = gpg_error_from_syserror (); goto out; } - arg_idx = 0; - - es_fputs ("(%s(%s", format); - arg_list[arg_idx++] = &key_identifier[secret]; - arg_list[arg_idx++] = &key_spec.identifier; - if (curve_name) - { - es_fputs ("(curve%s)", format); - arg_list[arg_idx++] = &curve_name; - } for (i = 0; i < elems_n; i++) { - es_fprintf (format, "(%c%%m)", elems[i]); - if (secret) + sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1); + if (!sublist) { - for (j = 0; j < elems_n; j++) - if (key_spec.elems_key_secret[j] == elems[i]) - break; + err = gpg_error (GPG_ERR_INV_SEXP); + break; } - else - j = i; - arg_list[arg_idx++] = &mpis[j]; - } - es_fputs (")(comment%s))", format); - arg_list[arg_idx++] = &comment; - arg_list[arg_idx] = NULL; - es_putc (0, format); - if (es_ferror (format)) - { - err = gpg_error_from_syserror (); - goto out; + sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG); + if (!sig_value) + { + err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */ + break; + } + gcry_sexp_release (sublist); + sublist = NULL; + + mpis[i] = sig_value; } - if (es_fclose_snatch (format, &formatbuf, NULL)) + if (err) + goto out; + + /* EdDSA specific. Actually TOTALLEN will always be 64. */ + + totallen = 0; + for (i = 0; i < DIM(data); i++) { - err = gpg_error_from_syserror (); - goto out; + err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &data[i], &data_n[i], mpis[i]); + if (err) + goto out; + totallen += data_n[i]; } - format = NULL; - err = gcry_sexp_build_array (&sexp_new, NULL, formatbuf, arg_list); + gcry_log_debug (" out: len=%zu\n", totallen); + err = stream_write_uint32 (stream, totallen); if (err) goto out; - *r_sexp = sexp_new; - err = 0; + for (i = 0; i < DIM(data); i++) + { + gcry_log_debughex (" out", data[i], data_n[i]); + err = stream_write_data (stream, data[i], data_n[i]); + if (err) + goto out; + } + + out: + for (i = 0; i < DIM(data); i++) + xfree (data[i]); + gcry_sexp_release (valuelist); + gcry_sexp_release (sublist); + mpint_list_free (mpis); + return err; +} + + +/* + S-Expressions. + */ + + +/* This function constructs a new S-Expression for the key identified + by the KEY_SPEC, SECRET, CURVE_NAME, MPIS, and COMMENT, which is to + be stored at R_SEXP. Returns an error code. */ +static gpg_error_t +sexp_key_construct (gcry_sexp_t *r_sexp, + ssh_key_type_spec_t key_spec, int secret, + const char *curve_name, gcry_mpi_t *mpis, + const char *comment) +{ + gpg_error_t err; + gcry_sexp_t sexp_new = NULL; + void *formatbuf = NULL; + void **arg_list = NULL; + estream_t format = NULL; + + + if ((key_spec.flags & SPEC_FLAG_IS_EdDSA)) + { + /* It is much easier and more readable to use a separate code + path for EdDSA. */ + if (!curve_name) + err = gpg_error (GPG_ERR_INV_CURVE); + else if (!mpis[0] || !gcry_mpi_get_flag (mpis[0], GCRYMPI_FLAG_OPAQUE)) + err = gpg_error (GPG_ERR_BAD_PUBKEY); + else if (secret + && (!mpis[1] + || !gcry_mpi_get_flag (mpis[1], GCRYMPI_FLAG_OPAQUE))) + err = gpg_error (GPG_ERR_BAD_SECKEY); + else if (secret) + err = gcry_sexp_build (&sexp_new, NULL, + "(private-key(ecc(curve %s)" + "(flags eddsa)(q %m)(d %m))" + "(comment%s))", + curve_name, + mpis[0], mpis[1], + comment? comment:""); + else + err = gcry_sexp_build (&sexp_new, NULL, + "(public-key(ecc(curve %s)" + "(flags eddsa)(q %m))" + "(comment%s))", + curve_name, + mpis[0], + comment? comment:""); + } + else + { + const char *key_identifier[] = { "public-key", "private-key" }; + int arg_idx; + const char *elems; + size_t elems_n; + unsigned int i, j; + + if (secret) + elems = key_spec.elems_sexp_order; + else + elems = key_spec.elems_key_public; + elems_n = strlen (elems); + + format = es_fopenmem (0, "a+b"); + if (!format) + { + err = gpg_error_from_syserror (); + goto out; + } + + /* Key identifier, algorithm identifier, mpis, comment, and a NULL + as a safeguard. */ + arg_list = xtrymalloc (sizeof (*arg_list) * (2 + 1 + elems_n + 1 + 1)); + if (!arg_list) + { + err = gpg_error_from_syserror (); + goto out; + } + arg_idx = 0; + + es_fputs ("(%s(%s", format); + arg_list[arg_idx++] = &key_identifier[secret]; + arg_list[arg_idx++] = &key_spec.identifier; + if (curve_name) + { + es_fputs ("(curve%s)", format); + arg_list[arg_idx++] = &curve_name; + } + + for (i = 0; i < elems_n; i++) + { + es_fprintf (format, "(%c%%m)", elems[i]); + if (secret) + { + for (j = 0; j < elems_n; j++) + if (key_spec.elems_key_secret[j] == elems[i]) + break; + } + else + j = i; + arg_list[arg_idx++] = &mpis[j]; + } + es_fputs (")(comment%s))", format); + arg_list[arg_idx++] = &comment; + arg_list[arg_idx] = NULL; + + es_putc (0, format); + if (es_ferror (format)) + { + err = gpg_error_from_syserror (); + goto out; + } + if (es_fclose_snatch (format, &formatbuf, NULL)) + { + err = gpg_error_from_syserror (); + goto out; + } + format = NULL; + + err = gcry_sexp_build_array (&sexp_new, NULL, formatbuf, arg_list); + } + + if (!err) + *r_sexp = sexp_new; out: es_fclose (format); @@ -1462,96 +1831,66 @@ sexp_key_construct (gcry_sexp_t *r_sexp, } -/* This functions breaks up the key contained in the S-Expression SEXP - according to KEY_SPEC. The MPIs are bundled in a newly create - list, which is to be stored in MPIS; a newly allocated string - holding the curve name may be stored at RCURVE, and a comment will - be stored at COMMENT; SECRET will be filled with a boolean flag - specifying what kind of key it is. Returns an error code. */ +/* This function extracts the key from the s-expression SEXP according + to KEY_SPEC and stores it in ssh format at (R_BLOB, R_BLOBLEN). If + WITH_SECRET is true, the secret key parts are also extracted if + possible. Returns 0 on success or an error code. Note that data + stored at R_BLOB must be freed using es_free! */ static gpg_error_t -sexp_key_extract (gcry_sexp_t sexp, - ssh_key_type_spec_t key_spec, int *secret, - gcry_mpi_t **mpis, char **r_curve, char **comment) +ssh_key_to_blob (gcry_sexp_t sexp, int with_secret, + ssh_key_type_spec_t key_spec, + void **r_blob, size_t *r_blob_size) { gpg_error_t err = 0; gcry_sexp_t value_list = NULL; gcry_sexp_t value_pair = NULL; - gcry_sexp_t comment_list = NULL; - unsigned int i; - char *comment_new = NULL; - const char *data; - size_t data_n; - int is_secret; - size_t elems_n; - const char *elems; - gcry_mpi_t *mpis_new = NULL; - gcry_mpi_t mpi; char *curve_name = NULL; + estream_t stream = NULL; + void *blob = NULL; + size_t blob_size; + const char *elems, *p_elems; + const char *data; + size_t datalen; - data = gcry_sexp_nth_data (sexp, 0, &data_n); - if (! data) + *r_blob = NULL; + *r_blob_size = 0; + + stream = es_fopenmem (0, "r+b"); + if (!stream) { - err = gpg_error (GPG_ERR_INV_SEXP); + err = gpg_error_from_syserror (); goto out; } - if ((data_n == 10 && !strncmp (data, "public-key", 10)) - || (data_n == 21 && !strncmp (data, "protected-private-key", 21)) - || (data_n == 20 && !strncmp (data, "shadowed-private-key", 20))) - { - is_secret = 0; - elems = key_spec.elems_key_public; - } - else if (data_n == 11 && !strncmp (data, "private-key", 11)) - { - is_secret = 1; - elems = key_spec.elems_key_secret; - } - else + /* Get the type of the key extpression. */ + data = gcry_sexp_nth_data (sexp, 0, &datalen); + if (!data) { err = gpg_error (GPG_ERR_INV_SEXP); goto out; } - elems_n = strlen (elems); - mpis_new = xtrycalloc (elems_n + 1, sizeof *mpis_new ); - if (!mpis_new) + if ((datalen == 10 && !strncmp (data, "public-key", 10)) + || (datalen == 21 && !strncmp (data, "protected-private-key", 21)) + || (datalen == 20 && !strncmp (data, "shadowed-private-key", 20))) + elems = key_spec.elems_key_public; + else if (datalen == 11 && !strncmp (data, "private-key", 11)) + elems = with_secret? key_spec.elems_key_secret : key_spec.elems_key_public; + else { - err = gpg_error_from_syserror (); + err = gpg_error (GPG_ERR_INV_SEXP); goto out; } + /* Get the algorithm identifier. */ value_list = gcry_sexp_find_token (sexp, key_spec.identifier, 0); - if (! value_list) + if (!value_list) { err = gpg_error (GPG_ERR_INV_SEXP); goto out; } - for (i = 0; i < elems_n; i++) - { - value_pair = gcry_sexp_find_token (value_list, elems + i, 1); - if (! value_pair) - { - err = gpg_error (GPG_ERR_INV_SEXP); - break; - } - - /* Note that we need to use STD format; i.e. prepend a 0x00 to - indicate a positive number if the high bit is set. */ - mpi = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_STD); - if (! mpi) - { - err = gpg_error (GPG_ERR_INV_SEXP); - break; - } - mpis_new[i] = mpi; - gcry_sexp_release (value_pair); - value_pair = NULL; - } - if (err) - goto out; - + /* Write the ssh algorithm identifier. */ if ((key_spec.flags & SPEC_FLAG_IS_ECDSA)) { /* Parse the "curve" parameter. We currently expect the curve @@ -1559,7 +1898,9 @@ sexp_key_extract (gcry_sexp_t sexp, easily be changed but then we need to find the curve name from the parameters using gcry_pk_get_curve. */ const char *mapped; + const char *sshname; + gcry_sexp_release (value_pair); value_pair = gcry_sexp_find_token (value_list, "curve", 5); if (!value_pair) { @@ -1593,48 +1934,87 @@ sexp_key_extract (gcry_sexp_t sexp, goto out; } } - gcry_sexp_release (value_pair); - value_pair = NULL; - } - /* We do not require a comment sublist to be present here. */ - data = NULL; - data_n = 0; + sshname = ssh_identifier_from_curve_name (curve_name); + if (!sshname) + { + err = gpg_error (GPG_ERR_UNKNOWN_CURVE); + goto out; + } + err = stream_write_cstring (stream, sshname); + if (err) + goto out; + err = stream_write_cstring (stream, curve_name); + if (err) + goto out; + } + else + { + /* Note: This is also used for EdDSA. */ + err = stream_write_cstring (stream, key_spec.ssh_identifier); + if (err) + goto out; + } - comment_list = gcry_sexp_find_token (sexp, "comment", 0); - if (comment_list) - data = gcry_sexp_nth_data (comment_list, 1, &data_n); - if (! data) + /* Write the parameters. */ + for (p_elems = elems; *p_elems; p_elems++) { - data = "(none)"; - data_n = 6; + gcry_sexp_release (value_pair); + value_pair = gcry_sexp_find_token (value_list, p_elems, 1); + if (!value_pair) + { + err = gpg_error (GPG_ERR_INV_SEXP); + goto out; + } + if ((key_spec.flags & SPEC_FLAG_IS_EdDSA)) + { + + data = gcry_sexp_nth_data (value_pair, 1, &datalen); + if (!data) + { + err = gpg_error (GPG_ERR_INV_SEXP); + goto out; + } + err = stream_write_string (stream, data, datalen); + if (err) + goto out; + } + else + { + gcry_mpi_t mpi; + + /* Note that we need to use STD format; i.e. prepend a 0x00 + to indicate a positive number if the high bit is set. */ + mpi = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_STD); + if (!mpi) + { + err = gpg_error (GPG_ERR_INV_SEXP); + goto out; + } + err = stream_write_mpi (stream, mpi); + gcry_mpi_release (mpi); + if (err) + goto out; + } } - comment_new = make_cstring (data, data_n); - if (! comment_new) + if (es_fclose_snatch (stream, &blob, &blob_size)) { err = gpg_error_from_syserror (); goto out; } + stream = NULL; - if (secret) - *secret = is_secret; - *mpis = mpis_new; - *comment = comment_new; - *r_curve = curve_name; + *r_blob = blob; + blob = NULL; + *r_blob_size = blob_size; out: - gcry_sexp_release (value_list); gcry_sexp_release (value_pair); - gcry_sexp_release (comment_list); - - if (err) - { - xfree (curve_name); - xfree (comment_new); - mpint_list_free (mpis_new); - } + xfree (curve_name); + es_fclose (stream); + es_free (blob); return err; } @@ -1702,6 +2082,11 @@ ssh_key_type_lookup (const char *ssh_name, const char *name, gpg_error_t err; unsigned int i; + /* FIXME: Although this sees to work, it not be correct if the + lookup is done via name which might be "ecc" but actually it need + to check the flags to see whether it is eddsa or ecdsa. Maybe + the entire parameter controlled logic is too complicated and we + would do better by just switching on the ssh_name. */ for (i = 0; i < DIM (ssh_key_types); i++) if ((ssh_name && (! strcmp (ssh_name, ssh_key_types[i].ssh_identifier))) || (name && (! strcmp (name, ssh_key_types[i].identifier)))) @@ -1719,23 +2104,6 @@ ssh_key_type_lookup (const char *ssh_name, const char *name, } -/* Lookup the ssh-identifier for the ECC curve CURVE_NAME. Returns - NULL if not found. */ -static const char * -ssh_identifier_from_curve_name (const char *curve_name) -{ - int i; - - for (i = 0; i < DIM (ssh_key_types); i++) - if (ssh_key_types[i].curve_name - && !strcmp (ssh_key_types[i].curve_name, curve_name)) - return ssh_key_types[i].ssh_identifier; - - return NULL; -} - - - /* Receive a key from STREAM, according to the key specification given as KEY_SPEC. Depending on SECRET, receive a secret or a public key. If READ_COMMENT is true, receive a comment string as well. @@ -1763,199 +2131,195 @@ ssh_receive_key (estream_t stream, gcry_sexp_t *key_new, int secret, if (err) goto out; - if ((spec.flags & SPEC_FLAG_IS_ECDSA)) + if ((spec.flags & SPEC_FLAG_IS_EdDSA)) { - /* The format of an ECDSA key is: - * string key_type ("ecdsa-sha2-nistp256" | - * "ecdsa-sha2-nistp384" | - * "ecdsa-sha2-nistp521" ) - * string ecdsa_curve_name - * string ecdsa_public_key - * mpint ecdsa_private + /* The format of an EdDSA key is: + * string key_type ("ssh-ed25519") + * string public_key + * string private_key * - * Note that we use the mpint reader instead of the string - * reader for ecsa_public_key. + * Note that the private key is the concatenation of the private + * key with the public key. Thus theres are 64 bytes; however + * we only want the real 32 byte private key - Libgcrypt expects + * this. */ - unsigned char *buffer; - const char *mapped; + mpi_list = xtrycalloc (3, sizeof *mpi_list); + if (!mpi_list) + { + err = gpg_error_from_syserror (); + goto out; + } - err = stream_read_string (stream, 0, &buffer, NULL); + err = stream_read_blob (stream, 0, &mpi_list[0]); if (err) goto out; - curve_name = buffer; - /* Fixme: Check that curve_name matches the keytype. */ - /* Because Libgcrypt < 1.6 has no support for the "nistpNNN" - curve names, we need to translate them here to Libgcrypt's - native names. */ - if (!strcmp (curve_name, "nistp256")) - mapped = "NIST P-256"; - else if (!strcmp (curve_name, "nistp384")) - mapped = "NIST P-384"; - else if (!strcmp (curve_name, "nistp521")) - mapped = "NIST P-521"; - else - mapped = NULL; - if (mapped) + if (secret) { - xfree (curve_name); - curve_name = xtrystrdup (mapped); - if (!curve_name) + u32 len = 0; + unsigned char *buffer; + + /* Read string length. */ + err = stream_read_uint32 (stream, &len); + if (err) + goto out; + if (len != 32 && len != 64) + { + err = gpg_error (GPG_ERR_BAD_SECKEY); + goto out; + } + buffer = xtrymalloc_secure (32); + if (!buffer) { err = gpg_error_from_syserror (); goto out; } + err = stream_read_data (stream, buffer, 32); + if (err) + { + xfree (buffer); + goto out; + } + mpi_list[1] = gcry_mpi_set_opaque (NULL, buffer, 8*32); + buffer = NULL; + if (len == 64) + { + err = stream_read_skip (stream, 32); + if (err) + goto out; + } } - } - - err = ssh_receive_mpint_list (stream, secret, spec, &mpi_list); - if (err) - goto out; - - if (read_comment) - { - err = stream_read_cstring (stream, &comment); - if (err) - goto out; - } - - if (secret) - elems = spec.elems_key_secret; - else - elems = spec.elems_key_public; - - if (spec.key_modifier) - { - err = (*spec.key_modifier) (elems, mpi_list); - if (err) - goto out; - } - - err = sexp_key_construct (&key, spec, secret, curve_name, mpi_list, - comment? comment:""); - if (err) - goto out; - - if (key_spec) - *key_spec = spec; - *key_new = key; - - out: - mpint_list_free (mpi_list); - xfree (curve_name); - xfree (key_type); - xfree (comment); - - return err; -} - -/* Converts a key of type TYPE, whose key material is given in MPIS, - into a newly created binary blob, which is to be stored in - BLOB/BLOB_SIZE. Returns zero on success or an error code. */ -static gpg_error_t -ssh_convert_key_to_blob (unsigned char **blob, size_t *blob_size, - ssh_key_type_spec_t *spec, - const char *curve_name, gcry_mpi_t *mpis) -{ - unsigned char *blob_new; - long int blob_size_new; - estream_t stream; - gpg_error_t err; - unsigned int i; - - *blob = NULL; - *blob_size = 0; - - blob_new = NULL; - stream = NULL; - err = 0; - - stream = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+"); - if (! stream) - { - err = gpg_error_from_syserror (); - goto out; } - - if ((spec->flags & SPEC_FLAG_IS_ECDSA) && curve_name) + else if ((spec.flags & SPEC_FLAG_IS_ECDSA)) { - const char *sshname = ssh_identifier_from_curve_name (curve_name); - if (!curve_name) - { - err = gpg_error (GPG_ERR_UNKNOWN_CURVE); - goto out; - } - err = stream_write_cstring (stream, sshname); + /* The format of an ECDSA key is: + * string key_type ("ecdsa-sha2-nistp256" | + * "ecdsa-sha2-nistp384" | + * "ecdsa-sha2-nistp521" ) + * string ecdsa_curve_name + * string ecdsa_public_key + * mpint ecdsa_private + * + * Note that we use the mpint reader instead of the string + * reader for ecsa_public_key. + */ + unsigned char *buffer; + const char *mapped; + + err = stream_read_string (stream, 0, &buffer, NULL); if (err) goto out; - err = stream_write_cstring (stream, curve_name); + curve_name = buffer; + /* Fixme: Check that curve_name matches the keytype. */ + /* Because Libgcrypt < 1.6 has no support for the "nistpNNN" + curve names, we need to translate them here to Libgcrypt's + native names. */ + if (!strcmp (curve_name, "nistp256")) + mapped = "NIST P-256"; + else if (!strcmp (curve_name, "nistp384")) + mapped = "NIST P-384"; + else if (!strcmp (curve_name, "nistp521")) + mapped = "NIST P-521"; + else + mapped = NULL; + if (mapped) + { + xfree (curve_name); + curve_name = xtrystrdup (mapped); + if (!curve_name) + { + err = gpg_error_from_syserror (); + goto out; + } + } + + err = ssh_receive_mpint_list (stream, secret, spec, &mpi_list); if (err) goto out; } else { - err = stream_write_cstring (stream, spec->ssh_identifier); + err = ssh_receive_mpint_list (stream, secret, spec, &mpi_list); if (err) goto out; } - for (i = 0; mpis[i]; i++) - if ((err = stream_write_mpi (stream, mpis[i]))) - goto out; - - blob_size_new = es_ftell (stream); - if (blob_size_new == -1) + if (read_comment) { - err = gpg_error_from_syserror (); - goto out; + err = stream_read_cstring (stream, &comment); + if (err) + goto out; } - err = es_fseek (stream, 0, SEEK_SET); - if (err) - goto out; + if (secret) + elems = spec.elems_key_secret; + else + elems = spec.elems_key_public; - blob_new = xtrymalloc (blob_size_new); - if (! blob_new) + if (spec.key_modifier) { - err = gpg_error_from_syserror (); - goto out; + err = (*spec.key_modifier) (elems, mpi_list); + if (err) + goto out; } - err = stream_read_data (stream, blob_new, blob_size_new); - if (err) - goto out; + if ((spec.flags & SPEC_FLAG_IS_EdDSA)) + { + if (secret) + { + err = gcry_sexp_build (&key, NULL, + "(private-key(ecc(curve \"Ed25519\")" + "(flags eddsa)(q %m)(d %m))" + "(comment%s))", + mpi_list[0], mpi_list[1], + comment? comment:""); + } + else + { + err = gcry_sexp_build (&key, NULL, + "(public-key(ecc(curve \"Ed25519\")" + "(flags eddsa)(q %m))" + "(comment%s))", + mpi_list[0], + comment? comment:""); + } + } + else + { + err = sexp_key_construct (&key, spec, secret, curve_name, mpi_list, + comment? comment:""); + if (err) + goto out; + } - *blob = blob_new; - *blob_size = blob_size_new; + if (key_spec) + *key_spec = spec; + *key_new = key; out: - - if (stream) - es_fclose (stream); - if (err) - xfree (blob_new); + mpint_list_free (mpi_list); + xfree (curve_name); + xfree (key_type); + xfree (comment); return err; } -/* Write the public key KEY_PUBLIC to STREAM in SSH key format. If +/* Write the public key from KEY to STREAM in SSH key format. If OVERRIDE_COMMENT is not NULL, it will be used instead of the comment stored in the key. */ static gpg_error_t -ssh_send_key_public (estream_t stream, - gcry_sexp_t key_public, +ssh_send_key_public (estream_t stream, gcry_sexp_t key, const char *override_comment) { ssh_key_type_spec_t spec; - gcry_mpi_t *mpi_list = NULL; char *key_type = NULL; - char *curve; char *comment = NULL; - unsigned char *blob = NULL; - size_t blob_n; + void *blob = NULL; + size_t bloblen; gpg_error_t err; - err = sexp_extract_identifier (key_public, &key_type); + err = sexp_extract_identifier (key, &key_type); if (err) goto out; @@ -1963,32 +2327,34 @@ ssh_send_key_public (estream_t stream, if (err) goto out; - err = sexp_key_extract (key_public, spec, NULL, &mpi_list, &curve, &comment); + err = ssh_key_to_blob (key, 0, spec, &blob, &bloblen); if (err) goto out; - err = ssh_convert_key_to_blob (&blob, &blob_n, &spec, curve, mpi_list); + err = stream_write_string (stream, blob, bloblen); if (err) goto out; - err = stream_write_string (stream, blob, blob_n); + if (override_comment) + err = stream_write_cstring (stream, override_comment); + else + { + err = ssh_key_extract_comment (key, &comment); + if (!err) + err = stream_write_cstring (stream, comment); + } if (err) goto out; - err = stream_write_cstring (stream, - override_comment? override_comment : comment); - out: - - mpint_list_free (mpi_list); - xfree (curve); - xfree (comment); xfree (key_type); - xfree (blob); + xfree (comment); + es_free (blob); return err; } + /* Read a public key out of BLOB/BLOB_SIZE according to the key specification given as KEY_SPEC, storing the new key in KEY_PUBLIC. Returns zero on success or an error code. */ @@ -2001,7 +2367,7 @@ ssh_read_key_public_from_blob (unsigned char *blob, size_t blob_size, gpg_error_t err; err = 0; - + /* FIXME: Use fopenmem_init */ blob_stream = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+"); if (! blob_stream) { @@ -2045,39 +2411,6 @@ ssh_key_grip (gcry_sexp_t key, unsigned char *buffer) } -/* Converts the secret key KEY_SECRET into a public key, storing it in - KEY_PUBLIC. SPEC is the according key specification. Returns zero - on success or an error code. */ -static gpg_error_t -key_secret_to_public (gcry_sexp_t *key_public, - ssh_key_type_spec_t spec, gcry_sexp_t key_secret) -{ - char *curve; - char *comment; - gcry_mpi_t *mpis; - gpg_error_t err; - int is_secret; - - comment = NULL; - mpis = NULL; - - err = sexp_key_extract (key_secret, spec, &is_secret, &mpis, - &curve, &comment); - if (err) - goto out; - - err = sexp_key_construct (key_public, spec, 0, curve, mpis, comment); - - out: - - mpint_list_free (mpis); - xfree (comment); - xfree (curve); - - return err; -} - - /* Check whether a smartcard is available and whether it has a usable key. Store a copy of that key at R_PK and return 0. If no key is available store NULL at R_PK and return an error code. If CARDSN @@ -2376,20 +2709,12 @@ ssh_handler_request_identities (ctrl_t ctrl, goto out; } - err = key_secret_to_public (&key_public, spec, key_secret); + err = ssh_send_key_public (key_blobs, key_secret, NULL); if (err) goto out; - gcry_sexp_release (key_secret); key_secret = NULL; - err = ssh_send_key_public (key_blobs, key_public, NULL); - if (err) - goto out; - - gcry_sexp_release (key_public); - key_public = NULL; - key_counter++; } err = 0; @@ -2441,30 +2766,27 @@ data_hash (unsigned char *data, size_t data_n, return 0; } -/* This function signs the data contained in CTRL, stores the created - signature in newly allocated memory in SIG and it's size in SIG_N; - SIG_ENCODER is the signature encoder to use. */ + +/* This function signs the data described by CTRL. If HASH is is not + NULL, (HASH,HASHLEN) overrides the hash stored in CTRL. This is to + allow the use of signature algorithms that implement the hashing + internally (e.g. Ed25519). On success the created signature is + stored in ssh format at R_SIG and it's size at R_SIGLEN; the caller + must use es_free to releaase this memory. */ static gpg_error_t data_sign (ctrl_t ctrl, ssh_key_type_spec_t *spec, - unsigned char **sig, size_t *sig_n) + const void *hash, size_t hashlen, + unsigned char **r_sig, size_t *r_siglen) { gpg_error_t err; gcry_sexp_t signature_sexp = NULL; estream_t stream = NULL; - gcry_sexp_t valuelist = NULL; - gcry_sexp_t sublist = NULL; - gcry_mpi_t sig_value = NULL; - unsigned char *sig_blob = NULL; - size_t sig_blob_n = 0; - int ret; - unsigned int i; - const char *elems; - size_t elems_n; - gcry_mpi_t *mpis = NULL; + void *blob = NULL; + size_t bloblen; char hexgrip[40+1]; - *sig = NULL; - *sig_n = 0; + *r_sig = NULL; + *r_siglen = 0; /* Quick check to see whether we have a valid keygrip and convert it to hex. */ @@ -2516,20 +2838,13 @@ data_sign (ctrl_t ctrl, ssh_key_type_spec_t *spec, "for the ssh key%%0A %F%%0A (%c)"), &signature_sexp, CACHE_MODE_SSH, ttl_from_sshcontrol, - NULL, 0); + hash, hashlen); ctrl->use_auth_call = 0; if (err) goto out; - valuelist = gcry_sexp_nth (signature_sexp, 1); - if (! valuelist) - { - err = gpg_error (GPG_ERR_INV_SEXP); - goto out; - } - - stream = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+"); - if (! stream) + stream = es_fopenmem (0, "r+b"); + if (!stream) { err = gpg_error_from_syserror (); goto out; @@ -2539,99 +2854,40 @@ data_sign (ctrl_t ctrl, ssh_key_type_spec_t *spec, if (err) goto out; - elems = spec->elems_signature; - elems_n = strlen (elems); - - mpis = xtrycalloc (elems_n + 1, sizeof *mpis); - if (!mpis) - { - err = gpg_error_from_syserror (); - goto out; - } - - for (i = 0; i < elems_n; i++) - { - sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1); - if (! sublist) - { - err = gpg_error (GPG_ERR_INV_SEXP); - break; - } - - sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG); - if (! sig_value) - { - err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */ - break; - } - gcry_sexp_release (sublist); - sublist = NULL; - - mpis[i] = sig_value; - } + err = spec->signature_encoder (spec, stream, signature_sexp); if (err) goto out; - err = spec->signature_encoder (spec, stream, mpis); - if (err) - goto out; - - sig_blob_n = es_ftell (stream); - if (sig_blob_n == -1) - { - err = gpg_error_from_syserror (); - goto out; - } - - sig_blob = xtrymalloc (sig_blob_n); - if (! sig_blob) - { - err = gpg_error_from_syserror (); - goto out; - } - - ret = es_fseek (stream, 0, SEEK_SET); - if (ret) - { - err = gpg_error_from_syserror (); - goto out; - } - - err = stream_read_data (stream, sig_blob, sig_blob_n); + err = es_fclose_snatch (stream, &blob, &bloblen); if (err) goto out; + stream = NULL; - *sig = sig_blob; - *sig_n = sig_blob_n; + *r_sig = blob; blob = NULL; + *r_siglen = bloblen; out: - - if (err) - xfree (sig_blob); - - if (stream) - es_fclose (stream); - gcry_sexp_release (valuelist); + xfree (blob); + es_fclose (stream); gcry_sexp_release (signature_sexp); - gcry_sexp_release (sublist); - mpint_list_free (mpis); return err; } + /* Handler for the "sign_request" command. */ static gpg_error_t ssh_handler_sign_request (ctrl_t ctrl, estream_t request, estream_t response) { - gcry_sexp_t key; + gcry_sexp_t key = NULL; ssh_key_type_spec_t spec; unsigned char hash[MAX_DIGEST_LEN]; unsigned int hash_n; unsigned char key_grip[20]; - unsigned char *key_blob; + unsigned char *key_blob = NULL; u32 key_blob_size; - unsigned char *data; - unsigned char *sig; + unsigned char *data = NULL; + unsigned char *sig = NULL; size_t sig_n; u32 data_size; u32 flags; @@ -2639,11 +2895,6 @@ ssh_handler_sign_request (ctrl_t ctrl, estream_t request, estream_t response) gpg_error_t ret_err; int hash_algo; - key_blob = NULL; - data = NULL; - sig = NULL; - key = NULL; - /* Receive key. */ err = stream_read_string (request, 0, &key_blob, &key_blob_size); @@ -2667,42 +2918,48 @@ ssh_handler_sign_request (ctrl_t ctrl, estream_t request, estream_t response) hash_algo = spec.hash_algo; if (!hash_algo) hash_algo = GCRY_MD_SHA1; /* Use the default. */ - - /* Hash data. */ - hash_n = gcry_md_get_algo_dlen (hash_algo); - if (! hash_n) - { - err = gpg_error (GPG_ERR_INTERNAL); - goto out; - } - err = data_hash (data, data_size, hash_algo, hash); - if (err) - goto out; - - /* Calculate key grip. */ - err = ssh_key_grip (key, key_grip); - if (err) - goto out; - - /* Sign data. */ - ctrl->digest.algo = hash_algo; - memcpy (ctrl->digest.value, hash, hash_n); - ctrl->digest.valuelen = hash_n; if ((spec.flags & SPEC_FLAG_USE_PKCS1V2)) ctrl->digest.raw_value = 0; else ctrl->digest.raw_value = 1; + + /* Calculate key grip. */ + err = ssh_key_grip (key, key_grip); + if (err) + goto out; ctrl->have_keygrip = 1; memcpy (ctrl->keygrip, key_grip, 20); - err = data_sign (ctrl, &spec, &sig, &sig_n); + /* Hash data unless we use EdDSA. */ + if ((spec.flags & SPEC_FLAG_IS_EdDSA)) + { + ctrl->digest.valuelen = 0; + } + else + { + hash_n = gcry_md_get_algo_dlen (hash_algo); + if (!hash_n) + { + err = gpg_error (GPG_ERR_INTERNAL); + goto out; + } + err = data_hash (data, data_size, hash_algo, hash); + if (err) + goto out; + memcpy (ctrl->digest.value, hash, hash_n); + ctrl->digest.valuelen = hash_n; + } - out: + /* Sign data. */ + if ((spec.flags & SPEC_FLAG_IS_EdDSA)) + err = data_sign (ctrl, &spec, data, data_size, &sig, &sig_n); + else + err = data_sign (ctrl, &spec, NULL, 0, &sig, &sig_n); + out: /* Done. */ - - if (! err) + if (!err) { ret_err = stream_write_byte (response, SSH_RESPONSE_SIGN_RESPONSE); if (ret_err) @@ -2713,6 +2970,8 @@ ssh_handler_sign_request (ctrl_t ctrl, estream_t request, estream_t response) } else { + log_error ("ssh sign request failed: %s <%s>\n", + gpg_strerror (err), gpg_strsource (err)); ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE); if (ret_err) goto leave; @@ -2723,54 +2982,35 @@ ssh_handler_sign_request (ctrl_t ctrl, estream_t request, estream_t response) gcry_sexp_release (key); xfree (key_blob); xfree (data); - xfree (sig); + es_free (sig); return ret_err; } + /* This function extracts the comment contained in the key - S-Expression KEY and stores a copy in COMMENT. Returns usual error + s-expression KEY and stores a copy in COMMENT. Returns usual error code. */ static gpg_error_t -ssh_key_extract_comment (gcry_sexp_t key, char **comment) +ssh_key_extract_comment (gcry_sexp_t key, char **r_comment) { gcry_sexp_t comment_list; - char *comment_new; - const char *data; - size_t data_n; - gpg_error_t err; - - comment_list = gcry_sexp_find_token (key, "comment", 0); - if (! comment_list) - { - err = gpg_error (GPG_ERR_INV_SEXP); - goto out; - } - - data = gcry_sexp_nth_data (comment_list, 1, &data_n); - if (! data) - { - err = gpg_error (GPG_ERR_INV_SEXP); - goto out; - } - - comment_new = make_cstring (data, data_n); - if (! comment_new) - { - err = gpg_error_from_syserror (); - goto out; - } - *comment = comment_new; - err = 0; + *r_comment = NULL; - out: + comment_list = gcry_sexp_find_token (key, "comment", 0); + if (!comment_list) + return gpg_error (GPG_ERR_INV_SEXP); + *r_comment = gcry_sexp_nth_string (comment_list, 1); gcry_sexp_release (comment_list); + if (!*r_comment) + return gpg_error (GPG_ERR_INV_SEXP); - return err; + return 0; } + /* This function converts the key contained in the S-Expression KEY into a buffer, which is protected by the passphrase PASSPHRASE. Returns usual error code. */ commit a77ed0f266d03e234027dda4de5a7f3dd6787b1e Author: Werner Koch Date: Sat Mar 22 20:51:16 2014 +0100 agent: Cleanups to prepare implementation of Ed25519. * agent/cvt-openpgp.c: Remove. (convert_to_openpgp): Use gcry_sexp_extract_param. * agent/findkey.c (is_eddsa): New. (agent_is_dsa_key, agent_is_eddsa_key): Check whether ecc means EdDSA. * agent/pksign.c (agent_pksign_do): Add args OVERRIDEDATA and OVERRIDEDATALEN. * common/ssh-utils.c (is_eddsa): New. (get_fingerprint): Take care or EdDSA. diff --git a/agent/agent.h b/agent/agent.h index eac7ba5..58e5841 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -368,7 +368,8 @@ char *agent_get_cache (const char *key, cache_mode_t cache_mode); int agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, gcry_sexp_t *signature_sexp, - cache_mode_t cache_mode, lookup_ttl_t lookup_ttl); + cache_mode_t cache_mode, lookup_ttl_t lookup_ttl, + const void *overridedata, size_t overridedatalen); int agent_pksign (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, membuf_t *outbuf, cache_mode_t cache_mode); diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 4191d6f..fb3b29a 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -2515,7 +2515,8 @@ data_sign (ctrl_t ctrl, ssh_key_type_spec_t *spec, _("Please enter the passphrase " "for the ssh key%%0A %F%%0A (%c)"), &signature_sexp, - CACHE_MODE_SSH, ttl_from_sshcontrol); + CACHE_MODE_SSH, ttl_from_sshcontrol, + NULL, 0); ctrl->use_auth_call = 0; if (err) goto out; diff --git a/agent/command.c b/agent/command.c index d1e53cd..fab27f0 100644 --- a/agent/command.c +++ b/agent/command.c @@ -2147,7 +2147,7 @@ cmd_export_key (assuan_context_t ctx, char *line) if (!ctrl->server_local->export_key) { - err = gpg_error (GPG_ERR_MISSING_KEY); + err = set_error (GPG_ERR_MISSING_KEY, "did you run KEYWRAP_KEY"); goto leave; } diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index 205b953..5718bd9 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -1030,46 +1030,6 @@ convert_from_openpgp_native (ctrl_t ctrl, } - -static gpg_error_t -key_from_sexp (gcry_sexp_t sexp, const char *elems, gcry_mpi_t *array) -{ - gpg_error_t err = 0; - gcry_sexp_t l2; - int idx; - - for (idx=0; *elems; elems++, idx++) - { - l2 = gcry_sexp_find_token (sexp, elems, 1); - if (!l2) - { - err = gpg_error (GPG_ERR_NO_OBJ); /* Required parameter not found. */ - goto leave; - } - array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (l2); - if (!array[idx]) - { - err = gpg_error (GPG_ERR_INV_OBJ); /* Required parameter invalid. */ - goto leave; - } - } - - leave: - if (err) - { - int i; - - for (i=0; i < idx; i++) - { - gcry_mpi_release (array[i]); - array[i] = NULL; - } - } - return err; -} - - /* Given an ARRAY of mpis with the key parameters, protect the secret parameters in that array and replace them by one opaque encoded mpi. NPKEY is the number of public key parameters and NSKEY is @@ -1173,7 +1133,6 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase, gpg_error_t err; gcry_sexp_t list, l2; char *name; - int algo; const char *algoname; const char *elems; int npkey, nskey; @@ -1203,26 +1162,63 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase, return gpg_error (GPG_ERR_INV_OBJ); /* Invalid structure of object. */ } - algo = gcry_pk_map_name (name); - xfree (name); - - switch (algo) + /* Map NAME to a name as used by Libgcrypt. We do not use the + Libgcrypt function here because we need a lowercase name and + require special treatment for some algorithms. */ + strlwr (name); + if (!strcmp (name, "rsa")) + { + algoname = "rsa"; + npkey = 2; + elems = "nedpqu"; + } + else if (!strcmp (name, "elg")) + { + algoname = "elg"; + npkey = 3; + elems = "pgyx"; + } + else if (!strcmp (name, "dsa")) + { + algoname = "dsa"; + npkey = 4; + elems = "pqgyx"; + } + else if (!strcmp (name, "ecc")) + { + algoname = "?"; /* Decide later by checking the usage. */ + npkey = 6; + elems = "pabgnqd"; + } + else if (!strcmp (name, "ecdsa")) + { + algoname = "ecdsa"; + npkey = 6; + elems = "pabgnqd"; + } + else if (!strcmp (name, "ecdh")) { - case GCRY_PK_RSA: algoname = "rsa"; npkey = 2; elems = "nedpqu"; break; - case GCRY_PK_ELG: algoname = "elg"; npkey = 3; elems = "pgyx"; break; - case GCRY_PK_ELG_E: algoname = "elg"; npkey = 3; elems = "pgyx"; break; - case GCRY_PK_DSA: algoname = "dsa"; npkey = 4; elems = "pqgyx"; break; - case GCRY_PK_ECDSA: algoname = "ecdsa"; npkey = 6; elems = "pabgnqd"; break; - case GCRY_PK_ECDH: algoname = "ecdh"; npkey = 6; elems = "pabgnqd"; break; - default: algoname = ""; npkey = 0; elems = NULL; break; + algoname = "ecdh"; + npkey = 6; + elems = "pabgnqd"; } + else + { + algoname = ""; + npkey = 0; + elems = NULL; + } + xfree (name); assert (!elems || strlen (elems) < DIM (array) ); nskey = elems? strlen (elems) : 0; + /* Extract the parameters and put them into an array. */ if (!elems) err = gpg_error (GPG_ERR_PUBKEY_ALGO); else - err = key_from_sexp (list, elems, array); + err = gcry_sexp_extract_param (list, NULL, elems, + array+0, array+1, array+2, array+3, array+4, + array+5, array+6, NULL); gcry_sexp_release (list); if (err) return err; diff --git a/agent/findkey.c b/agent/findkey.c index 7b24c55..84d2cfd 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -688,7 +688,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, string describing the names of the parameters. ALGONAMESIZE and ELEMSSIZE give the allocated size of the provided buffers. The buffers may be NULL if not required. If R_LIST is not NULL the top - level list will be stored tehre; the caller needs to release it in + level list will be stored there; the caller needs to release it in this case. */ static gpg_error_t key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list, @@ -776,27 +776,65 @@ key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list, } +/* Return true if KEYPARMS holds an EdDSA key. */ +static int +is_eddsa (gcry_sexp_t keyparms) +{ + int result = 0; + gcry_sexp_t list; + const char *s; + size_t n; + int i; + + list = gcry_sexp_find_token (keyparms, "flags", 0); + for (i = list ? gcry_sexp_length (list)-1 : 0; i > 0; i--) + { + s = gcry_sexp_nth_data (list, i, &n); + if (!s) + continue; /* Not a data element. */ + + if (n == 5 && !memcmp (s, "eddsa", 5)) + { + result = 1; + break; + } + } + gcry_sexp_release (list); + return result; +} + + /* Return the public key algorithm number if S_KEY is a DSA style key. If it is not a DSA style key, return 0. */ int agent_is_dsa_key (gcry_sexp_t s_key) { + int result; + gcry_sexp_t list; char algoname[6]; if (!s_key) return 0; - if (key_parms_from_sexp (s_key, NULL, algoname, sizeof algoname, NULL, 0)) + if (key_parms_from_sexp (s_key, &list, algoname, sizeof algoname, NULL, 0)) return 0; /* Error - assume it is not an DSA key. */ if (!strcmp (algoname, "dsa")) - return GCRY_PK_DSA; + result = GCRY_PK_DSA; else if (!strcmp (algoname, "ecc")) - return GCRY_PK_ECDSA; /* FIXME: Check for the EdDSA flag. */ + { + if (is_eddsa (list)) + result = 0; + else + result = GCRY_PK_ECDSA; + } else if (!strcmp (algoname, "ecdsa")) - return GCRY_PK_ECDSA; + result = GCRY_PK_ECDSA; else - return 0; + result = 0; + + gcry_sexp_release (list); + return result; } @@ -804,18 +842,25 @@ agent_is_dsa_key (gcry_sexp_t s_key) int agent_is_eddsa_key (gcry_sexp_t s_key) { + int result; + gcry_sexp_t list; char algoname[6]; if (!s_key) return 0; - if (key_parms_from_sexp (s_key, NULL, algoname, sizeof algoname, NULL, 0)) + if (key_parms_from_sexp (s_key, &list, algoname, sizeof algoname, NULL, 0)) return 0; /* Error - assume it is not an EdDSA key. */ - if (!strcmp (algoname, "eddsa")) - return 1; + if (!strcmp (algoname, "ecc") && is_eddsa (list)) + result = 1; + else if (!strcmp (algoname, "eddsa")) /* backward compatibility. */ + result = 1; else - return 0; + result = 0; + + gcry_sexp_release (list); + return result; } diff --git a/agent/pksign.c b/agent/pksign.c index 0886150..fb593a6 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -276,18 +276,35 @@ do_encode_raw_pkcs1 (const byte *md, size_t mdlen, unsigned int nbits, the signature S-expression. LOOKUP is an optional function to provide a way for lower layers to ask for the caching TTL. If a CACHE_NONCE is given that cache item is first tried to get a - passphrase. */ + passphrase. If OVERRIDEDATA is not NULL, OVERRIDEDATALEN bytes + from this buffer are used instead of the data in CTRL. The + override feature is required to allow the use of Ed25519 with ssh + because Ed25519 dies the hashing itself. */ int agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, gcry_sexp_t *signature_sexp, - cache_mode_t cache_mode, lookup_ttl_t lookup_ttl) + cache_mode_t cache_mode, lookup_ttl_t lookup_ttl, + const void *overridedata, size_t overridedatalen) { gcry_sexp_t s_skey = NULL, s_sig = NULL; unsigned char *shadow_info = NULL; unsigned int rc = 0; /* FIXME: gpg-error? */ + const unsigned char *data; + int datalen; - if (! ctrl->have_keygrip) + if (overridedata) + { + data = overridedata; + datalen = overridedatalen; + } + else + { + data = ctrl->digest.value; + datalen = ctrl->digest.valuelen; + } + + if (!ctrl->have_keygrip) return gpg_error (GPG_ERR_NO_SECKEY); rc = agent_key_from_file (ctrl, cache_nonce, desc_text, ctrl->keygrip, @@ -315,8 +332,7 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, is_ECDSA = 1; rc = divert_pksign (ctrl, - ctrl->digest.value, - ctrl->digest.valuelen, + data, datalen, ctrl->digest.algo, shadow_info, &buf, &len); if (rc) @@ -405,22 +421,18 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, /* Put the hash into a sexp */ if (agent_is_eddsa_key (s_skey)) - rc = do_encode_eddsa (ctrl->digest.value, - ctrl->digest.valuelen, + rc = do_encode_eddsa (data, datalen, &s_hash); else if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1) - rc = do_encode_raw_pkcs1 (ctrl->digest.value, - ctrl->digest.valuelen, + rc = do_encode_raw_pkcs1 (data, datalen, gcry_pk_get_nbits (s_skey), &s_hash); else if ( (dsaalgo = agent_is_dsa_key (s_skey)) ) - rc = do_encode_dsa (ctrl->digest.value, - ctrl->digest.valuelen, + rc = do_encode_dsa (data, datalen, dsaalgo, s_skey, &s_hash); else - rc = do_encode_md (ctrl->digest.value, - ctrl->digest.valuelen, + rc = do_encode_md (data, datalen, ctrl->digest.algo, &s_hash, ctrl->digest.raw_value); @@ -468,7 +480,8 @@ agent_pksign (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, size_t len = 0; int rc = 0; - rc = agent_pksign_do (ctrl, cache_nonce, desc_text, &s_sig, cache_mode, NULL); + rc = agent_pksign_do (ctrl, cache_nonce, desc_text, &s_sig, cache_mode, NULL, + NULL, 0); if (rc) goto leave; diff --git a/common/ssh-utils.c b/common/ssh-utils.c index 0c71567..a75b3c0 100644 --- a/common/ssh-utils.c +++ b/common/ssh-utils.c @@ -37,6 +37,33 @@ #include "ssh-utils.h" +/* Return true if KEYPARMS holds an EdDSA key. */ +static int +is_eddsa (gcry_sexp_t keyparms) +{ + int result = 0; + gcry_sexp_t list; + const char *s; + size_t n; + int i; + + list = gcry_sexp_find_token (keyparms, "flags", 0); + for (i = list ? gcry_sexp_length (list)-1 : 0; i > 0; i--) + { + s = gcry_sexp_nth_data (list, i, &n); + if (!s) + continue; /* Not a data element. */ + + if (n == 5 && !memcmp (s, "eddsa", 5)) + { + result = 1; + break; + } + } + gcry_sexp_release (list); + return result; +} + /* Return the Secure Shell type fingerprint for KEY. The length of the fingerprint is returned at R_LEN and the fingerprint itself at @@ -53,6 +80,7 @@ get_fingerprint (gcry_sexp_t key, void **r_fpr, size_t *r_len, int as_string) int idx; const char *elems; gcry_md_hd_t md = NULL; + int blobmode = 0; *r_fpr = NULL; *r_len = 0; @@ -93,38 +121,52 @@ get_fingerprint (gcry_sexp_t key, void **r_fpr, size_t *r_len, int as_string) elems = "en"; gcry_md_write (md, "\0\0\0\x07ssh-rsa", 11); break; + case GCRY_PK_DSA: elems = "pqgy"; gcry_md_write (md, "\0\0\0\x07ssh-dss", 11); break; - case GCRY_PK_ECDSA: - /* We only support the 3 standard curves for now. It is just a - quick hack. */ - elems = "q"; - gcry_md_write (md, "\0\0\0\x13" "ecdsa-sha2-nistp", 20); - l2 = gcry_sexp_find_token (list, "curve", 0); - if (!l2) - elems = ""; + + case GCRY_PK_ECC: + if (is_eddsa (list)) + { + elems = "q"; + blobmode = 1; + /* For now there is just one curve, thus no need to switch + on it. */ + gcry_md_write (md, "\0\0\0\x0b" "ssh-ed25519", 15); + } else { - gcry_free (name); - name = gcry_sexp_nth_string (l2, 1); - gcry_sexp_release (l2); - l2 = NULL; - if (!name) + /* We only support the 3 standard curves for now. It is + just a quick hack. */ + elems = "q"; + gcry_md_write (md, "\0\0\0\x13" "ecdsa-sha2-nistp", 20); + l2 = gcry_sexp_find_token (list, "curve", 0); + if (!l2) elems = ""; - else if (!strcmp (name, "NIST P-256") || !strcmp (name, "nistp256")) - gcry_md_write (md, "256\0\0\0\x08nistp256", 15); - else if (!strcmp (name, "NIST P-384") || !strcmp (name, "nistp384")) - gcry_md_write (md, "384\0\0\0\x08nistp521", 15); - else if (!strcmp (name, "NIST P-521") || !strcmp (name, "nistp521")) - gcry_md_write (md, "521\0\0\0\x08nistp521", 15); else - elems = ""; + { + gcry_free (name); + name = gcry_sexp_nth_string (l2, 1); + gcry_sexp_release (l2); + l2 = NULL; + if (!name) + elems = ""; + else if (!strcmp (name, "NIST P-256")||!strcmp (name, "nistp256")) + gcry_md_write (md, "256\0\0\0\x08nistp256", 15); + else if (!strcmp (name, "NIST P-384")||!strcmp (name, "nistp384")) + gcry_md_write (md, "384\0\0\0\x08nistp521", 15); + else if (!strcmp (name, "NIST P-521")||!strcmp (name, "nistp521")) + gcry_md_write (md, "521\0\0\0\x08nistp521", 15); + else + elems = ""; + } + if (!*elems) + err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_CURVE); } - if (!*elems) - err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_CURVE); break; + default: elems = ""; err = gpg_err_make (default_errsource, GPG_ERR_PUBKEY_ALGO); @@ -133,33 +175,56 @@ get_fingerprint (gcry_sexp_t key, void **r_fpr, size_t *r_len, int as_string) if (err) goto leave; + for (idx = 0, s = elems; *s; s++, idx++) { - gcry_mpi_t a; - unsigned char *buf; - size_t buflen; - l2 = gcry_sexp_find_token (list, s, 1); if (!l2) { err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP); goto leave; } - a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (l2); - l2 = NULL; - if (!a) + if (blobmode) { - err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP); - goto leave; + const char *blob; + size_t bloblen; + unsigned char lenbuf[4]; + + blob = gcry_sexp_nth_data (l2, 1, &bloblen); + if (!blob) + { + err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP); + goto leave; + } + lenbuf[0] = bloblen >> 24; + lenbuf[1] = bloblen >> 16; + lenbuf[2] = bloblen >> 8; + lenbuf[3] = bloblen; + gcry_md_write (md, lenbuf, 4); + gcry_md_write (md, blob, bloblen); } + else + { + gcry_mpi_t a; + unsigned char *buf; + size_t buflen; - err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, &buf, &buflen, a); - gcry_mpi_release (a); - if (err) - goto leave; - gcry_md_write (md, buf, buflen); - gcry_free (buf); + a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); + gcry_sexp_release (l2); + l2 = NULL; + if (!a) + { + err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP); + goto leave; + } + + err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, &buf, &buflen, a); + gcry_mpi_release (a); + if (err) + goto leave; + gcry_md_write (md, buf, buflen); + gcry_free (buf); + } } *r_fpr = gcry_malloc (as_string? 61:20); commit 6376227a31b3076321ce16ad626b333057bda53d Author: Werner Koch Date: Tue Mar 18 16:49:38 2014 +0100 tools: Fix NULL deref in gpg-connect-agent. * tools/gpg-connect-agent.c (handle_inquire): Do not pass NULL to strlen. diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c index 42e315c..81e981b 100644 --- a/tools/gpg-connect-agent.c +++ b/tools/gpg-connect-agent.c @@ -1936,7 +1936,10 @@ handle_inquire (assuan_context_t ctx, char *line) if (d->is_var) { char *tmpvalue = get_var_ext (d->file); - rc = assuan_send_data (ctx, tmpvalue, strlen (tmpvalue)); + if (tmpvalue) + rc = assuan_send_data (ctx, tmpvalue, strlen (tmpvalue)); + else + rc = assuan_send_data (ctx, "", 0); xfree (tmpvalue); if (rc) log_error ("sending data back failed: %s\n", gpg_strerror (rc) ); ----------------------------------------------------------------------- Summary of changes: agent/agent.h | 3 +- agent/command-ssh.c | 1365 ++++++++++++++++++++++++++------------------- agent/command.c | 2 +- agent/cvt-openpgp.c | 102 ++-- agent/findkey.c | 65 ++- agent/pksign.c | 41 +- common/ssh-utils.c | 141 +++-- tools/gpg-connect-agent.c | 5 +- 8 files changed, 1044 insertions(+), 680 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Sat Mar 22 21:29:06 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Sat, 22 Mar 2014 21:29:06 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-370-gfc3e70c Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via fc3e70c11342267c1062e4244955d19ecd72e0f6 (commit) from 072432883ededa15bf35f80102e0572746ba4af1 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit fc3e70c11342267c1062e4244955d19ecd72e0f6 Author: Werner Koch Date: Sat Mar 22 21:28:35 2014 +0100 agent: Put ssh key type as comment into sshcontrol. * agent/command-ssh.c (ssh_key_type_spec): Add field name. (ssh_key_types): Add human readable names. (add_control_entry): Add arg SPEC and print key type as comment. (ssh_identity_register): Add arg SPEC. (ssh_handler_add_identity): Add var SPEC and pass ssh_receive_key. diff --git a/agent/command-ssh.c b/agent/command-ssh.c index be2ab3b..5d7186f 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -148,6 +148,9 @@ struct ssh_key_type_spec /* Algorithm identifier as used by OpenSSH. */ const char *ssh_identifier; + /* Human readable name of the algorithm. */ + const char *name; + /* Algorithm identifier as used by GnuPG. */ const char *identifier; @@ -271,32 +274,32 @@ static ssh_request_spec_t request_specs[] = static ssh_key_type_spec_t ssh_key_types[] = { { - "ssh-ed25519", "ecc", "qd", "q", "rs", "qd", + "ssh-ed25519", "Ed25519", "ecc", "qd", "q", "rs", "qd", NULL, ssh_signature_encoder_eddsa, "Ed25519", 0, SPEC_FLAG_IS_EdDSA }, { - "ssh-rsa", "rsa", "nedupq", "en", "s", "nedpqu", + "ssh-rsa", "RSA", "rsa", "nedupq", "en", "s", "nedpqu", ssh_key_modifier_rsa, ssh_signature_encoder_rsa, NULL, 0, SPEC_FLAG_USE_PKCS1V2 }, { - "ssh-dss", "dsa", "pqgyx", "pqgy", "rs", "pqgyx", + "ssh-dss", "DSA", "dsa", "pqgyx", "pqgy", "rs", "pqgyx", NULL, ssh_signature_encoder_dsa, NULL, 0, 0 }, { - "ecdsa-sha2-nistp256", "ecdsa", "qd", "q", "rs", "qd", + "ecdsa-sha2-nistp256", "ECDSA", "ecdsa", "qd", "q", "rs", "qd", NULL, ssh_signature_encoder_ecdsa, "nistp256", GCRY_MD_SHA256, SPEC_FLAG_IS_ECDSA }, { - "ecdsa-sha2-nistp384", "ecdsa", "qd", "q", "rs", "qd", + "ecdsa-sha2-nistp384", "ECDSA", "ecdsa", "qd", "q", "rs", "qd", NULL, ssh_signature_encoder_ecdsa, "nistp384", GCRY_MD_SHA384, SPEC_FLAG_IS_ECDSA }, { - "ecdsa-sha2-nistp521", "ecdsa", "qd", "q", "rs", "qd", + "ecdsa-sha2-nistp521", "ECDSA", "ecdsa", "qd", "q", "rs", "qd", NULL, ssh_signature_encoder_ecdsa, "nistp521", GCRY_MD_SHA512, SPEC_FLAG_IS_ECDSA } @@ -1061,7 +1064,8 @@ search_control_file (ssh_control_file_t cf, const char *hexgrip, general used to add a key received through the ssh-add function. We can assume that the user wants to allow ssh using this key. */ static gpg_error_t -add_control_entry (ctrl_t ctrl, const char *hexgrip, const char *fmtfpr, +add_control_entry (ctrl_t ctrl, ssh_key_type_spec_t *spec, + const char *hexgrip, const char *fmtfpr, int ttl, int confirm) { gpg_error_t err; @@ -1084,9 +1088,10 @@ add_control_entry (ctrl_t ctrl, const char *hexgrip, const char *fmtfpr, opened in append mode, we simply need to write to it. */ tp = localtime (&atime); fprintf (cf->fp, - ("# Key added on: %04d-%02d-%02d %02d:%02d:%02d\n" - "# Fingerprint: %s\n" + ("# %s key added on: %04d-%02d-%02d %02d:%02d:%02d\n" + "# MD5 Fingerprint: %s\n" "%s %d%s\n"), + spec->name, 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec, fmtfpr, hexgrip, ttl, confirm? " confirm":""); @@ -3064,7 +3069,8 @@ reenter_compare_cb (struct pin_entry_info_s *pi) our key storage, don't do anything. When entering a new key also add an entry to the sshcontrol file. */ static gpg_error_t -ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl, int confirm) +ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec, + gcry_sexp_t key, int ttl, int confirm) { gpg_error_t err; unsigned char key_grip_raw[20]; @@ -3158,7 +3164,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl, int confirm) goto out; /* And add an entry to the sshcontrol file. */ - err = add_control_entry (ctrl, key_grip, key_fpr, ttl, confirm); + err = add_control_entry (ctrl, spec, key_grip, key_fpr, ttl, confirm); out: @@ -3202,6 +3208,7 @@ static gpg_error_t ssh_handler_add_identity (ctrl_t ctrl, estream_t request, estream_t response) { gpg_error_t ret_err; + ssh_key_type_spec_t spec; gpg_error_t err; gcry_sexp_t key; unsigned char b; @@ -3213,7 +3220,7 @@ ssh_handler_add_identity (ctrl_t ctrl, estream_t request, estream_t response) ttl = 0; /* FIXME? */ - err = ssh_receive_key (request, &key, 1, 1, NULL); + err = ssh_receive_key (request, &key, 1, 1, &spec); if (err) goto out; @@ -3252,7 +3259,7 @@ ssh_handler_add_identity (ctrl_t ctrl, estream_t request, estream_t response) if (err) goto out; - err = ssh_identity_register (ctrl, key, ttl, confirm); + err = ssh_identity_register (ctrl, &spec, key, ttl, confirm); out: ----------------------------------------------------------------------- Summary of changes: agent/command-ssh.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Thu Mar 27 17:41:09 2014 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 27 Mar 2014 17:41:09 +0100 Subject: [git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-373-gb6786cc Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via b6786cc3ec0bb582323adf94c2ee624bcfbeb466 (commit) via 4f50ec98ddd57253cae66e2321f0cc98ee189a09 (commit) via 5c2a50cdc90e85b1fc380851ccfbe9186969b658 (commit) from fc3e70c11342267c1062e4244955d19ecd72e0f6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b6786cc3ec0bb582323adf94c2ee624bcfbeb466 Author: Werner Koch Date: Thu Mar 27 16:33:40 2014 +0100 gpg: Add commands --quick-sign-key and --quick-lsign-key. * g10/gpg.c (main): Add commands --quick-sign-key and --quick-lsign-key. * g10/keyedit.c (sign_uids): Add args FP and QUICK. (keyedit_quick_sign): New. (show_key_with_all_names): Add arg NOWARN. diff --git a/doc/gpg.texi b/doc/gpg.texi index 91186f2..607a611 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -906,6 +906,24 @@ Signs a public key with your secret key but marks it as non-exportable. This is a shortcut version of the subcommand "lsign" from @option{--edit-key}. + at ifset gpgtwoone + at item --quick-sign-key @code{fpr} [@code{names}] + at itemx --quick-lsign-key @code{name} + at opindex quick-sign-key + at opindex quick-lsign-key +Directly sign a key from the passphrase without any further user +interaction. The @code{fpr} must be the verified primary fingerprint +of a key in the local keyring. If no @code{names} are given, all +useful user ids are signed; with given [@code{names}] only useful user +ids matching one of theses names are signed. The command + at option{--quick-lsign-key} marks the signatures as non-exportable. + +This command uses reasonable defaults and thus does not provide the +full flexibility of the "sign" subcommand from @option{--edit-key}. +Its intended use to help unattended signing using a list of verified +fingerprints. + at end ifset + @ifclear gpgone @item --passwd @var{user_id} @opindex passwd diff --git a/g10/gpg.c b/g10/gpg.c index 7529e81..daae3d3 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -1,6 +1,7 @@ /* gpg.c - The GnuPG utility (main for gpg) * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 * 2008, 2009, 2010, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013, 2014 Werner Koch * * This file is part of GnuPG. * @@ -111,6 +112,8 @@ enum cmd_and_opt_values aSignSym, aSignKey, aLSignKey, + aQuickSignKey, + aQuickLSignKey, aListConfig, aGPGConfList, aGPGConfTest, @@ -408,6 +411,10 @@ static ARGPARSE_OPTS opts[] = { N_("remove keys from the public keyring")), ARGPARSE_c (aDeleteSecretKeys, "delete-secret-keys", N_("remove keys from the secret keyring")), + ARGPARSE_c (aQuickSignKey, "quick-sign-key" , + N_("quickly sign a key")), + ARGPARSE_c (aQuickLSignKey, "quick-lsign-key", + N_("quickly sign a key locally")), ARGPARSE_c (aSignKey, "sign-key" ,N_("sign a key")), ARGPARSE_c (aLSignKey, "lsign-key" ,N_("sign a key locally")), ARGPARSE_c (aEditKey, "edit-key" ,N_("sign or edit a key")), @@ -2264,6 +2271,8 @@ main (int argc, char **argv) case aDeArmor: case aEnArmor: case aSign: + case aQuickSignKey: + case aQuickLSignKey: case aSignKey: case aLSignKey: case aStore: @@ -3735,6 +3744,22 @@ main (int argc, char **argv) } break; + case aQuickSignKey: + case aQuickLSignKey: + { + const char *fpr; + + if (argc < 1) + wrong_args ("--quick-[l]sign-key fingerprint [userids]"); + fpr = *argv++; argc--; + sl = NULL; + for( ; argc; argc--, argv++) + append_to_strlist2 (&sl, *argv, utf8_strings); + keyedit_quick_sign (ctrl, fpr, sl, locusr, (cmd == aQuickLSignKey)); + free_strlist (sl); + } + break; + case aSignKey: if( argc != 1 ) wrong_args(_("--sign-key user-id")); diff --git a/g10/keyedit.c b/g10/keyedit.c index b7f7ad6..c4d7ca8 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -56,7 +56,8 @@ static void show_names (estream_t fp, KBNODE keyblock, PKT_public_key * pk, static void show_key_with_all_names (estream_t fp, KBNODE keyblock, int only_marked, int with_revoker, int with_fpr, - int with_subkeys, int with_prefs); + int with_subkeys, int with_prefs, + int nowarn); static void show_key_and_fingerprint (KBNODE keyblock); static int menu_adduid (KBNODE keyblock, int photo, const char *photo_name); static void menu_deluid (KBNODE pub_keyblock); @@ -499,13 +500,16 @@ trustsig_prompt (byte * trust_value, byte * trust_depth, char **regexp) /* - * Loop over all LOCUSR and and sign the uids after asking. - * If no user id is marked, all user ids will be signed; - * if some user_ids are marked those will be signed. + * Loop over all LOCUSR and and sign the uids after asking. If no + * user id is marked, all user ids will be signed; if some user_ids + * are marked only those will be signed. If QUICK is true the + * function won't ask the user and use sensible defaults. */ static int -sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, - int local, int nonrevocable, int trust, int interactive) +sign_uids (estream_t fp, + kbnode_t keyblock, strlist_t locusr, int *ret_modified, + int local, int nonrevocable, int trust, int interactive, + int quick) { int rc = 0; SK_LIST sk_list = NULL; @@ -518,13 +522,15 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, /* Are there any non-v3 sigs on this key already? */ if (PGP2) - for (node = keyblock; node; node = node->next) - if (node->pkt->pkttype == PKT_SIGNATURE && - node->pkt->pkt.signature->version > 3) - { - all_v3 = 0; - break; - } + { + for (node = keyblock; node; node = node->next) + if (node->pkt->pkttype == PKT_SIGNATURE && + node->pkt->pkt.signature->version > 3) + { + all_v3 = 0; + break; + } + } /* Build a list of all signators. * @@ -595,13 +601,13 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, if (uidnode->pkt->pkt.user_id->is_revoked) { - tty_printf (_("User ID \"%s\" is revoked."), user); + tty_fprintf (fp, _("User ID \"%s\" is revoked."), user); if (selfsig) - tty_printf ("\n"); - else if (opt.expert) + tty_fprintf (fp, "\n"); + else if (opt.expert && !quick) { - tty_printf ("\n"); + tty_fprintf (fp, "\n"); /* No, so remove the mark and continue */ if (!cpr_get_answer_is_yes ("sign_uid.revoke_okay", _("Are you sure you " @@ -618,18 +624,18 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; - tty_printf (_(" Unable to sign.\n")); + tty_fprintf (fp, _(" Unable to sign.\n")); } } else if (uidnode->pkt->pkt.user_id->is_expired) { - tty_printf (_("User ID \"%s\" is expired."), user); + tty_fprintf (fp, _("User ID \"%s\" is expired."), user); if (selfsig) - tty_printf ("\n"); - else if (opt.expert) + tty_fprintf (fp, "\n"); + else if (opt.expert && !quick) { - tty_printf ("\n"); + tty_fprintf (fp, "\n"); /* No, so remove the mark and continue */ if (!cpr_get_answer_is_yes ("sign_uid.expire_okay", _("Are you sure you " @@ -646,17 +652,17 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; - tty_printf (_(" Unable to sign.\n")); + tty_fprintf (fp, _(" Unable to sign.\n")); } } else if (!uidnode->pkt->pkt.user_id->created && !selfsig) { - tty_printf (_("User ID \"%s\" is not self-signed."), - user); + tty_fprintf (fp, _("User ID \"%s\" is not self-signed."), + user); - if (opt.expert) + if (opt.expert && !quick) { - tty_printf ("\n"); + tty_fprintf (fp, "\n"); /* No, so remove the mark and continue */ if (!cpr_get_answer_is_yes ("sign_uid.nosig_okay", _("Are you sure you " @@ -673,13 +679,14 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; - tty_printf (_(" Unable to sign.\n")); + tty_fprintf (fp, _(" Unable to sign.\n")); } } - if (uidnode && interactive && !yesreally) + if (uidnode && interactive && !yesreally && !quick) { - tty_printf (_("User ID \"%s\" is signable. "), user); + tty_fprintf (fp, + _("User ID \"%s\" is signable. "), user); if (!cpr_get_answer_is_yes ("sign_uid.sign_okay", _("Sign it? (y/N) "))) { @@ -704,10 +711,12 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, uidnode->pkt->pkt.user_id->len, 0); /* It's a v3 self-sig. Make it into a v4 self-sig? */ - if (node->pkt->pkt.signature->version < 4 && selfsig) + if (node->pkt->pkt.signature->version < 4 + && selfsig && !quick) { - tty_printf (_("The self-signature on \"%s\"\n" - "is a PGP 2.x-style signature.\n"), user); + tty_fprintf (fp, + _("The self-signature on \"%s\"\n" + "is a PGP 2.x-style signature.\n"), user); /* Note that the regular PGP2 warning below still applies if there are no v4 sigs on @@ -729,10 +738,10 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, /* Is the current signature expired? */ if (node->pkt->pkt.signature->flags.expired) { - tty_printf (_("Your current signature on \"%s\"\n" - "has expired.\n"), user); + tty_fprintf (fp, _("Your current signature on \"%s\"\n" + "has expired.\n"), user); - if (cpr_get_answer_is_yes + if (quick || cpr_get_answer_is_yes ("sign_uid.replace_expired_okay", _("Do you want to issue a " "new signature to replace " @@ -755,10 +764,12 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, { /* It's a local sig, and we want to make a exportable sig. */ - tty_printf (_("Your current signature on \"%s\"\n" - "is a local signature.\n"), user); + tty_fprintf (fp, _("Your current signature on \"%s\"\n" + "is a local signature.\n"), user); - if (cpr_get_answer_is_yes + if (quick) + ; + else if (cpr_get_answer_is_yes ("sign_uid.local_promote_okay", _("Do you want to promote " "it to a full exportable " "signature? (y/N) "))) @@ -779,14 +790,15 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, /* Fixme: see whether there is a revocation in which * case we should allow to sign it again. */ if (!node->pkt->pkt.signature->flags.exportable && local) - tty_printf - (_("\"%s\" was already locally signed by key %s\n"), + tty_fprintf ( fp, + _("\"%s\" was already locally signed by key %s\n"), user, keystr_from_pk (pk)); else - tty_printf (_("\"%s\" was already signed by key %s\n"), + tty_fprintf (fp, + _("\"%s\" was already signed by key %s\n"), user, keystr_from_pk (pk)); - if (opt.expert + if (opt.expert && !quick && cpr_get_answer_is_yes ("sign_uid.dupe_okay", _("Do you want to sign it " "again anyway? (y/N) "))) @@ -810,15 +822,15 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, /* Check whether any uids are left for signing. */ if (!count_uids_with_flag (keyblock, NODFLG_MARK_A)) { - tty_printf (_("Nothing to sign with key %s\n"), + tty_fprintf (fp, _("Nothing to sign with key %s\n"), keystr_from_pk (pk)); continue; } /* Ask whether we really should sign these user id(s). */ - tty_printf ("\n"); - show_key_with_all_names (NULL, keyblock, 1, 0, 1, 0, 0); - tty_printf ("\n"); + tty_fprintf (fp, "\n"); + show_key_with_all_names (fp, keyblock, 1, 0, 1, 0, 0, 0); + tty_fprintf (fp, "\n"); if (primary_pk->expiredate && !selfsig) { @@ -826,11 +838,11 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, if (primary_pk->expiredate <= now) { - tty_printf (_("This key has expired!")); + tty_fprintf (fp, _("This key has expired!")); - if (opt.expert) + if (opt.expert && !quick) { - tty_printf (" "); + tty_fprintf (fp, " "); if (!cpr_get_answer_is_yes ("sign_uid.expired_okay", _("Are you sure you still " "want to sign it? (y/N) "))) @@ -838,16 +850,16 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, } else { - tty_printf (_(" Unable to sign.\n")); + tty_fprintf (fp, _(" Unable to sign.\n")); continue; } } else { - tty_printf (_("This key is due to expire on %s.\n"), - expirestr_from_pk (primary_pk)); + tty_fprintf (fp, _("This key is due to expire on %s.\n"), + expirestr_from_pk (primary_pk)); - if (opt.ask_cert_expire) + if (opt.ask_cert_expire && !quick) { char *answer = cpr_get ("sign_uid.expire", _("Do you want your signature to " @@ -875,7 +887,7 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, the expiration of the pk */ if (!duration && !selfsig) { - if (opt.ask_cert_expire) + if (opt.ask_cert_expire && !quick) duration = ask_expire_interval (1, opt.def_cert_expire); else duration = parse_expire_string (opt.def_cert_expire); @@ -890,11 +902,11 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, if (PGP2 && all_v3 && (pk->version > 3 || force_v4) && primary_pk->version <= 3) { - tty_printf (_("You may not make an OpenPGP signature on a " - "PGP 2.x key while in --pgp2 mode.\n")); - tty_printf (_("This would make the key unusable in PGP 2.x.\n")); + tty_fprintf (fp, _("You may not make an OpenPGP signature on a " + "PGP 2.x key while in --pgp2 mode.\n")); + tty_fprintf (fp, _("This would make the key unusable in PGP 2.x.\n")); - if (opt.expert) + if (opt.expert && !quick) { if (!cpr_get_answer_is_yes ("sign_uid.v4_on_v3_okay", _("Are you sure you still " @@ -911,26 +923,28 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, ; else { - if (opt.batch || !opt.ask_cert_level) + if (opt.batch || !opt.ask_cert_level || quick) class = 0x10 + opt.def_cert_level; else { char *answer; - tty_printf (_("How carefully have you verified the key you are " + tty_fprintf (fp, + _("How carefully have you verified the key you are " "about to sign actually belongs\nto the person " "named above? If you don't know what to " "answer, enter \"0\".\n")); - tty_printf ("\n"); - tty_printf (_(" (0) I will not answer.%s\n"), + tty_fprintf (fp, "\n"); + tty_fprintf (fp, _(" (0) I will not answer.%s\n"), opt.def_cert_level == 0 ? " (default)" : ""); - tty_printf (_(" (1) I have not checked at all.%s\n"), + tty_fprintf (fp, _(" (1) I have not checked at all.%s\n"), opt.def_cert_level == 1 ? " (default)" : ""); - tty_printf (_(" (2) I have done casual checking.%s\n"), + tty_fprintf (fp, _(" (2) I have done casual checking.%s\n"), opt.def_cert_level == 2 ? " (default)" : ""); - tty_printf (_(" (3) I have done very careful checking.%s\n"), + tty_fprintf (fp, + _(" (3) I have done very careful checking.%s\n"), opt.def_cert_level == 3 ? " (default)" : ""); - tty_printf ("\n"); + tty_fprintf (fp, "\n"); while (class == 0) { @@ -948,79 +962,85 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, else if (ascii_strcasecmp (answer, "3") == 0) class = 0x13; /* Positive */ else - tty_printf (_("Invalid selection.\n")); + tty_fprintf (fp, _("Invalid selection.\n")); xfree (answer); } } - if (trust) + if (trust && !quick) trustsig_prompt (&trust_value, &trust_depth, &trust_regexp); } - p = get_user_id_native (sk_keyid); - tty_printf (_("Are you sure that you want to sign this key with your\n" - "key \"%s\" (%s)\n"), p, keystr_from_pk (pk)); - xfree (p); + if (!quick) + { + p = get_user_id_native (sk_keyid); + tty_fprintf (fp, + _("Are you sure that you want to sign this key with your\n" + "key \"%s\" (%s)\n"), p, keystr_from_pk (pk)); + xfree (p); + } if (selfsig) { - tty_printf ("\n"); - tty_printf (_("This will be a self-signature.\n")); + tty_fprintf (fp, "\n"); + tty_fprintf (fp, _("This will be a self-signature.\n")); if (local) { - tty_printf ("\n"); - tty_printf (_("WARNING: the signature will not be marked " - "as non-exportable.\n")); + tty_fprintf (fp, "\n"); + tty_fprintf (fp, _("WARNING: the signature will not be marked " + "as non-exportable.\n")); } if (nonrevocable) { - tty_printf ("\n"); - tty_printf (_("WARNING: the signature will not be marked " - "as non-revocable.\n")); + tty_fprintf (fp, "\n"); + tty_fprintf (fp, _("WARNING: the signature will not be marked " + "as non-revocable.\n")); } } else { if (local) { - tty_printf ("\n"); - tty_printf - (_("The signature will be marked as non-exportable.\n")); + tty_fprintf (fp, "\n"); + tty_fprintf (fp, + _("The signature will be marked as non-exportable.\n")); } if (nonrevocable) { - tty_printf ("\n"); - tty_printf - (_("The signature will be marked as non-revocable.\n")); + tty_fprintf (fp, "\n"); + tty_fprintf (fp, + _("The signature will be marked as non-revocable.\n")); } switch (class) { case 0x11: - tty_printf ("\n"); - tty_printf (_("I have not checked this key at all.\n")); + tty_fprintf (fp, "\n"); + tty_fprintf (fp, _("I have not checked this key at all.\n")); break; case 0x12: - tty_printf ("\n"); - tty_printf (_("I have checked this key casually.\n")); + tty_fprintf (fp, "\n"); + tty_fprintf (fp, _("I have checked this key casually.\n")); break; case 0x13: - tty_printf ("\n"); - tty_printf (_("I have checked this key very carefully.\n")); + tty_fprintf (fp, "\n"); + tty_fprintf (fp, _("I have checked this key very carefully.\n")); break; } } - tty_printf ("\n"); + tty_fprintf (fp, "\n"); if (opt.batch && opt.answer_yes) ; + else if (quick) + ; else if (!cpr_get_answer_is_yes ("sign_uid.okay", _("Really sign? (y/N) "))) continue; @@ -1093,7 +1113,7 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, delete_kbnode (node); } /* End loop over signators. */ -leave: + leave: release_sk_list (sk_list); return rc; } @@ -1544,7 +1564,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, if (redisplay && !quiet) { - show_key_with_all_names (NULL, keyblock, 0, 1, 0, 1, 0); + show_key_with_all_names (NULL, keyblock, 0, 1, 0, 1, 0, 0); tty_printf ("\n"); redisplay = 0; } @@ -1736,8 +1756,8 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, break; } - sign_uids (keyblock, locusr, &modified, - localsig, nonrevokesig, trustsig, interactive); + sign_uids (NULL, keyblock, locusr, &modified, + localsig, nonrevokesig, trustsig, interactive, 0); } break; @@ -2083,7 +2103,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, break; } - show_key_with_all_names (NULL, keyblock, 0, 0, 0, 1, 0); + show_key_with_all_names (NULL, keyblock, 0, 0, 0, 1, 0, 0); tty_printf ("\n"); if (edit_ownertrust (find_kbnode (keyblock, PKT_PUBLIC_KEY)->pkt->pkt. @@ -2284,6 +2304,163 @@ leave: } +/* Unattended key signing function. If the key specifified by FPR is + availabale and FPR is the primary fingerprint all user ids of the + user ids of the key are signed using the default signing key. If + UIDS is an empty list all usable UIDs are signed, if it is not + empty, only those user ids matching one of the entries of the loist + are signed. With LOCAL being true kthe signatures are marked as + non-exportable. */ +void +keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids, + strlist_t locusr, int local) +{ + gpg_error_t err; + kbnode_t keyblock = NULL; + KEYDB_HANDLE kdbhd = NULL; + int modified = 0; + KEYDB_SEARCH_DESC desc; + PKT_public_key *pk; + kbnode_t node; + strlist_t sl; + int any; + +#ifdef HAVE_W32_SYSTEM + /* See keyedit_menu for why we need this. */ + check_trustdb_stale (); +#endif + + /* We require a fingerprint because only this uniquely identifies a + key and may thus be used to select a key for unattended key + signing. */ + if (classify_user_id (fpr, &desc, 1) + || !(desc.mode == KEYDB_SEARCH_MODE_FPR + || desc.mode == KEYDB_SEARCH_MODE_FPR16 + || desc.mode == KEYDB_SEARCH_MODE_FPR20)) + { + log_error (_("\"%s\" is not a fingerprint\n"), fpr); + goto leave; + } + err = get_pubkey_byname (ctrl, NULL, NULL, fpr, &keyblock, &kdbhd, 1, 1); + if (err) + { + log_error (_("key \"%s\" not found: %s\n"), fpr, gpg_strerror (err)); + goto leave; + } + if (fix_keyblock (keyblock)) + modified++; + if (collapse_uids (&keyblock)) + modified++; + reorder_keyblock (keyblock); + + /* Check that the primary fingerprint has been given. */ + { + byte fprbin[MAX_FINGERPRINT_LEN]; + size_t fprlen; + + fingerprint_from_pk (keyblock->pkt->pkt.public_key, fprbin, &fprlen); + if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR16 + && !memcmp (fprbin, desc.u.fpr, 16)) + ; + else if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR + && !memcmp (fprbin, desc.u.fpr, 16) + && !desc.u.fpr[16] + && !desc.u.fpr[17] + && !desc.u.fpr[18] + && !desc.u.fpr[19]) + ; + else if (fprlen == 20 && (desc.mode == KEYDB_SEARCH_MODE_FPR20 + || desc.mode == KEYDB_SEARCH_MODE_FPR) + && !memcmp (fprbin, desc.u.fpr, 20)) + ; + else + { + log_error (_("\"%s\" is not the primary fingerprint\n"), fpr); + goto leave; + } + } + + /* If we modified the keyblock, make sure the flags are right. */ + if (modified) + merge_keys_and_selfsig (keyblock); + + /* Give some info in verbose. */ + if (opt.verbose) + { + show_key_with_all_names (es_stdout, keyblock, 0, + 1/*with_revoker*/, 1/*with_fingerprint*/, + 0, 0, 1); + es_fflush (es_stdout); + } + + pk = keyblock->pkt->pkt.public_key; + if (pk->flags.revoked) + { + if (!opt.verbose) + show_key_with_all_names (es_stdout, keyblock, 0, 0, 0, 0, 0, 1); + log_error ("%s%s", _("Key is revoked."), _(" Unable to sign.\n")); + goto leave; + } + + /* Set the flags according to the UIDS list. Fixme: We may want to + use classify_user_id along with dedicated compare functions so + that we match the same way as in the key lookup. */ + any = 0; + menu_select_uid (keyblock, 0); /* Better clear the flags first. */ + for (sl=uids; sl; sl = sl->next) + { + for (node = keyblock; node; node = node->next) + { + if (node->pkt->pkttype == PKT_USER_ID) + { + PKT_user_id *uid = node->pkt->pkt.user_id; + + if (!uid->attrib_data + && ascii_memistr (uid->name, uid->len, sl->d)) + { + node->flag |= NODFLG_SELUID; + any = 1; + } + } + } + } + + if (uids && !any) + { + if (!opt.verbose) + show_key_with_all_names (es_stdout, keyblock, 0, 0, 0, 0, 0, 1); + es_fflush (es_stdout); + log_error ("%s %s", _("No matching user IDs."), _("Nothing to sign.\n")); + goto leave; + } + + /* Sign. */ + sign_uids (es_stdout, keyblock, locusr, &modified, local, 0, 0, 0, 1); + es_fflush (es_stdout); + + if (modified) + { + err = keydb_update_keyblock (kdbhd, keyblock); + if (err) + { + log_error (_("update failed: %s\n"), gpg_strerror (err)); + goto leave; + } + } + else + log_info (_("Key not changed so no update needed.\n")); + + if (update_trust) + revalidation_mark (); + + + leave: + release_kbnode (keyblock); + keydb_release (kdbhd); +} + + + static void tty_print_notations (int indent, PKT_signature * sig) { @@ -2705,7 +2882,8 @@ show_names (estream_t fp, static void show_key_with_all_names (estream_t fp, KBNODE keyblock, int only_marked, int with_revoker, - int with_fpr, int with_subkeys, int with_prefs) + int with_fpr, int with_subkeys, int with_prefs, + int nowarn) { KBNODE node; int i; @@ -2889,7 +3067,7 @@ show_key_with_all_names (estream_t fp, show_names (fp, keyblock, primary, only_marked ? NODFLG_MARK_A : 0, with_prefs); - if (do_warn) + if (do_warn && !nowarn) tty_fprintf (fp, _("Please note that the shown key validity" " is not necessarily correct\n" "unless you restart the program.\n")); diff --git a/g10/main.h b/g10/main.h index ad1a9f6..ce77a83 100644 --- a/g10/main.h +++ b/g10/main.h @@ -236,6 +236,8 @@ int delete_keys( strlist_t names, int secret, int allow_both ); void keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, strlist_t commands, int quiet, int seckey_check ); void keyedit_passwd (ctrl_t ctrl, const char *username); +void keyedit_quick_sign (ctrl_t ctrl, const char *fpr, + strlist_t uids, strlist_t locusr, int local); void show_basic_key_info (KBNODE keyblock); /*-- keygen.c --*/ commit 4f50ec98ddd57253cae66e2321f0cc98ee189a09 Author: Werner Koch Date: Thu Mar 27 12:59:55 2014 +0100 Change some keyedit functions to allow printing to arbitrary streams. * common/ttyio.c (tty_print_string): Add optional arg FP. Change all callers. (tty_print_utf8_string2): Ditto. * g10/keyedit.c (show_prefs): Ditto. (show_key_with_all_names_colon): Ditto. (show_names): Ditto. * g10/keylist.c (print_revokers): Ditto. (print_fingerprint): Ditto. diff --git a/common/ttyio.c b/common/ttyio.c index 66ca984..dee11cb 100644 --- a/common/ttyio.c +++ b/common/ttyio.c @@ -310,53 +310,101 @@ tty_fprintf (estream_t fp, const char *fmt, ... ) /**************** - * Print a string, but filter all control characters out. + * Print a string, but filter all control characters out. If FP is + * not NULL print to that stream instead to the tty. */ void -tty_print_string ( const byte *p, size_t n ) +tty_print_string (estream_t fp, const byte *p, size_t n ) { - if (no_terminal) + if (no_terminal && !fp) return; - if( !initialized ) + if( !initialized & !fp) init_ttyfp(); #ifdef USE_W32_CONSOLE /* not so effective, change it if you want */ - for( ; n; n--, p++ ) - if( iscntrl( *p ) ) { - if( *p == '\n' ) - tty_printf("\\n"); - else if( !*p ) - tty_printf("\\0"); - else - tty_printf("\\x%02x", *p); - } - else - tty_printf("%c", *p); + if (fp) + { + for( ; n; n--, p++ ) + { + if( iscntrl( *p ) ) + { + if( *p == '\n' ) + tty_fprintf (fp, "\\n"); + else if( !*p ) + tty_fprintf (fp, "\\0"); + else + tty_fprintf (fp, "\\x%02x", *p); + } + else + tty_fprintf (fp, "%c", *p); + } + } + else + { + for( ; n; n--, p++ ) + { + if( iscntrl( *p ) ) + { + if( *p == '\n' ) + tty_printf ("\\n"); + else if( !*p ) + tty_printf ("\\0"); + else + tty_printf ("\\x%02x", *p); + } + else + tty_printf ("%c", *p); + } + } #else - for( ; n; n--, p++ ) - if( iscntrl( *p ) ) { - putc('\\', ttyfp); - if( *p == '\n' ) - putc('n', ttyfp); - else if( !*p ) - putc('0', ttyfp); - else - fprintf(ttyfp, "x%02x", *p ); - } - else - putc(*p, ttyfp); + if (fp) + { + for( ; n; n--, p++ ) + { + if (iscntrl (*p)) + { + es_putc ('\\', fp); + if ( *p == '\n' ) + es_putc ('n', fp); + else if ( !*p ) + es_putc ('0', fp); + else + es_fprintf (fp, "x%02x", *p); + } + else + es_putc (*p, fp); + } + } + else + { + for (; n; n--, p++) + { + if (iscntrl (*p)) + { + putc ('\\', ttyfp); + if ( *p == '\n' ) + putc ('n', ttyfp); + else if ( !*p ) + putc ('0', ttyfp); + else + fprintf (ttyfp, "x%02x", *p ); + } + else + putc (*p, ttyfp); + } + } #endif } void -tty_print_utf8_string2( const byte *p, size_t n, size_t max_n ) +tty_print_utf8_string2 (estream_t fp, const byte *p, size_t n, size_t max_n) { size_t i; char *buf; - if (no_terminal) + if (no_terminal && !fp) return; /* we can handle plain ascii simpler, so check for it first */ @@ -370,21 +418,22 @@ tty_print_utf8_string2( const byte *p, size_t n, size_t max_n ) buf[max_n] = 0; } /*(utf8 conversion already does the control character quoting)*/ - tty_printf("%s", buf ); - xfree( buf ); + tty_fprintf (fp, "%s", buf); + xfree (buf); } else { if( max_n && (n > max_n) ) { n = max_n; } - tty_print_string( p, n ); + tty_print_string (fp, p, n ); } } + void tty_print_utf8_string( const byte *p, size_t n ) { - tty_print_utf8_string2( p, n, 0 ); + tty_print_utf8_string2 (NULL, p, n, 0); } diff --git a/common/ttyio.h b/common/ttyio.h index 5c810b8..0a66d86 100644 --- a/common/ttyio.h +++ b/common/ttyio.h @@ -47,9 +47,10 @@ void tty_printf (const char *fmt, ... ); void tty_fprintf (estream_t fp, const char *fmt, ... ); char *tty_getf (const char *promptfmt, ... ); #endif -void tty_print_string (const unsigned char *p, size_t n); +void tty_print_string (estream_t fp, const unsigned char *p, size_t n); void tty_print_utf8_string (const unsigned char *p, size_t n); -void tty_print_utf8_string2 (const unsigned char *p, size_t n, size_t max_n); +void tty_print_utf8_string2 (estream_t fp, + const unsigned char *p, size_t n, size_t max_n); char *tty_get (const char *prompt); char *tty_get_hidden (const char *prompt); void tty_kill_prompt (void); diff --git a/g10/card-util.c b/g10/card-util.c index c043b3e..411a4d4 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -269,7 +269,7 @@ print_name (estream_t fp, const char *text, const char *name) if (fp) print_utf8_buffer2 (fp, name, strlen (name), '\n'); else - tty_print_utf8_string2 (name, strlen (name), 0); + tty_print_utf8_string2 (NULL, name, strlen (name), 0); } else tty_fprintf (fp, _("[not set]")); @@ -302,7 +302,7 @@ print_isoname (estream_t fp, const char *text, else if (fp) print_utf8_buffer2 (fp, given, strlen (given), '\n'); else - tty_print_utf8_string2 (given, strlen (given), 0); + tty_print_utf8_string2 (NULL, given, strlen (given), 0); if (opt.with_colons) es_putc (':', fp); @@ -315,7 +315,7 @@ print_isoname (estream_t fp, const char *text, else if (fp) print_utf8_buffer2 (fp, buf, strlen (buf), '\n'); else - tty_print_utf8_string2 (buf, strlen (buf), 0); + tty_print_utf8_string2 (NULL, buf, strlen (buf), 0); xfree (buf); } else diff --git a/g10/keyedit.c b/g10/keyedit.c index 47a2234..b7f7ad6 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1,6 +1,7 @@ /* keyedit.c - keyedit stuff * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * 2008, 2009, 2010 Free Software Foundation, Inc. + * Copyright (C) 2013, 2014 Werner Koch * * This file is part of GnuPG. * @@ -50,9 +51,10 @@ static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose); -static void show_names (KBNODE keyblock, PKT_public_key * pk, +static void show_names (estream_t fp, KBNODE keyblock, PKT_public_key * pk, unsigned int flag, int with_prefs); -static void show_key_with_all_names (KBNODE keyblock, int only_marked, +static void show_key_with_all_names (estream_t fp, + KBNODE keyblock, int only_marked, int with_revoker, int with_fpr, int with_subkeys, int with_prefs); static void show_key_and_fingerprint (KBNODE keyblock); @@ -252,7 +254,7 @@ print_and_check_one_sig (KBNODE keyblock, KBNODE node, { size_t n; char *p = get_user_id (sig->keyid, &n); - tty_print_utf8_string2 (p, n, + tty_print_utf8_string2 (NULL, p, n, opt.screen_columns - keystrlen () - 26 - ((opt. list_options & LIST_SHOW_SIG_EXPIRE) ? 11 @@ -815,7 +817,7 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified, /* Ask whether we really should sign these user id(s). */ tty_printf ("\n"); - show_key_with_all_names (keyblock, 1, 0, 1, 0, 0); + show_key_with_all_names (NULL, keyblock, 1, 0, 1, 0, 0); tty_printf ("\n"); if (primary_pk->expiredate && !selfsig) @@ -1542,7 +1544,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, if (redisplay && !quiet) { - show_key_with_all_names (keyblock, 0, 1, 0, 1, 0); + show_key_with_all_names (NULL, keyblock, 0, 1, 0, 1, 0); tty_printf ("\n"); redisplay = 0; } @@ -2081,7 +2083,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, break; } - show_key_with_all_names (keyblock, 0, 0, 0, 1, 0); + show_key_with_all_names (NULL, keyblock, 0, 0, 0, 1, 0); tty_printf ("\n"); if (edit_ownertrust (find_kbnode (keyblock, PKT_PUBLIC_KEY)->pkt->pkt. @@ -2100,7 +2102,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, { int count = count_selected_uids (keyblock); assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY); - show_names (keyblock, keyblock->pkt->pkt.public_key, + show_names (NULL, keyblock, keyblock->pkt->pkt.public_key, count ? NODFLG_SELUID : 0, 1); } break; @@ -2109,7 +2111,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, { int count = count_selected_uids (keyblock); assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY); - show_names (keyblock, keyblock->pkt->pkt.public_key, + show_names (NULL, keyblock, keyblock->pkt->pkt.public_key, count ? NODFLG_SELUID : 0, 2); } break; @@ -2482,13 +2484,16 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose) opt.with_colons is used. It prints all available data in a easy to parse format and does not translate utf8 */ static void -show_key_with_all_names_colon (KBNODE keyblock) +show_key_with_all_names_colon (estream_t fp, kbnode_t keyblock) { KBNODE node; int i, j, ulti_hack = 0; byte pk_version = 0; PKT_public_key *primary = NULL; + if (!fp) + fp = es_stdout; + /* the keys */ for (node = keyblock; node; node = node->next) { @@ -2506,46 +2511,46 @@ show_key_with_all_names_colon (KBNODE keyblock) keyid_from_pk (pk, keyid); - fputs (node->pkt->pkttype == PKT_PUBLIC_KEY ? "pub:" : "sub:", - stdout); + es_fputs (node->pkt->pkttype == PKT_PUBLIC_KEY ? "pub:" : "sub:", + fp); if (!pk->flags.valid) - putchar ('i'); + es_putc ('i', fp); else if (pk->flags.revoked) - putchar ('r'); + es_putc ('r', fp); else if (pk->has_expired) - putchar ('e'); + es_putc ('e', fp); else if (!(opt.fast_list_mode || opt.no_expensive_trust_checks)) { int trust = get_validity_info (pk, NULL); if (trust == 'u') ulti_hack = 1; - putchar (trust); + es_putc (trust, fp); } - printf (":%u:%d:%08lX%08lX:%lu:%lu::", - nbits_from_pk (pk), - pk->pubkey_algo, - (ulong) keyid[0], (ulong) keyid[1], - (ulong) pk->timestamp, (ulong) pk->expiredate); + es_fprintf (fp, ":%u:%d:%08lX%08lX:%lu:%lu::", + nbits_from_pk (pk), + pk->pubkey_algo, + (ulong) keyid[0], (ulong) keyid[1], + (ulong) pk->timestamp, (ulong) pk->expiredate); if (node->pkt->pkttype == PKT_PUBLIC_KEY && !(opt.fast_list_mode || opt.no_expensive_trust_checks)) - putchar (get_ownertrust_info (pk)); - putchar (':'); - putchar (':'); - putchar (':'); + es_putc (get_ownertrust_info (pk), fp); + es_putc (':', fp); + es_putc (':', fp); + es_putc (':', fp); /* Print capabilities. */ if ((pk->pubkey_usage & PUBKEY_USAGE_ENC)) - putchar ('e'); + es_putc ('e', fp); if ((pk->pubkey_usage & PUBKEY_USAGE_SIG)) - putchar ('s'); + es_putc ('s', fp); if ((pk->pubkey_usage & PUBKEY_USAGE_CERT)) - putchar ('c'); + es_putc ('c', fp); if ((pk->pubkey_usage & PUBKEY_USAGE_AUTH)) - putchar ('a'); - putchar ('\n'); + es_putc ('a', fp); + es_putc ('\n', fp); - print_fingerprint (pk, 0); - print_revokers (pk); + print_fingerprint (fp, pk, 0); + print_revokers (fp, pk); } } @@ -2560,16 +2565,16 @@ show_key_with_all_names_colon (KBNODE keyblock) ++i; if (uid->attrib_data) - printf ("uat:"); + es_fputs ("uat:", fp); else - printf ("uid:"); + es_fputs ("uid:", fp); if (uid->is_revoked) - printf ("r::::::::"); + es_fputs ("r::::::::", fp); else if (uid->is_expired) - printf ("e::::::::"); + es_fputs ("e::::::::", fp); else if (opt.fast_list_mode || opt.no_expensive_trust_checks) - printf ("::::::::"); + es_fputs ("::::::::", fp); else { int uid_validity; @@ -2578,19 +2583,19 @@ show_key_with_all_names_colon (KBNODE keyblock) uid_validity = get_validity_info (primary, uid); else uid_validity = 'u'; - printf ("%c::::::::", uid_validity); + es_fprintf (fp, "%c::::::::", uid_validity); } if (uid->attrib_data) - printf ("%u %lu", uid->numattribs, uid->attrib_len); + es_fprintf (fp, "%u %lu", uid->numattribs, uid->attrib_len); else - es_write_sanitized (es_stdout, uid->name, uid->len, ":", NULL); + es_write_sanitized (fp, uid->name, uid->len, ":", NULL); - putchar (':'); + es_putc (':', fp); /* signature class */ - putchar (':'); + es_putc (':', fp); /* capabilities */ - putchar (':'); + es_putc (':', fp); /* preferences */ if (pk_version > 3 || uid->selfsigversion > 3) { @@ -2599,38 +2604,41 @@ show_key_with_all_names_colon (KBNODE keyblock) for (j = 0; prefs && prefs[j].type; j++) { if (j) - putchar (' '); - printf ("%c%d", prefs[j].type == PREFTYPE_SYM ? 'S' : - prefs[j].type == PREFTYPE_HASH ? 'H' : - prefs[j].type == PREFTYPE_ZIP ? 'Z' : '?', - prefs[j].value); + es_putc (' ', fp); + es_fprintf (fp, + "%c%d", prefs[j].type == PREFTYPE_SYM ? 'S' : + prefs[j].type == PREFTYPE_HASH ? 'H' : + prefs[j].type == PREFTYPE_ZIP ? 'Z' : '?', + prefs[j].value); } if (uid->flags.mdc) - printf (",mdc"); + es_fputs (",mdc", fp); if (!uid->flags.ks_modify) - printf (",no-ks-modify"); + es_fputs (",no-ks-modify", fp); } - putchar (':'); + es_putc (':', fp); /* flags */ - printf ("%d,", i); + es_fprintf (fp, "%d,", i); if (uid->is_primary) - putchar ('p'); + es_putc ('p', fp); if (uid->is_revoked) - putchar ('r'); + es_putc ('r', fp); if (uid->is_expired) - putchar ('e'); + es_putc ('e', fp); if ((node->flag & NODFLG_SELUID)) - putchar ('s'); + es_putc ('s', fp); if ((node->flag & NODFLG_MARK_A)) - putchar ('m'); - putchar (':'); - putchar ('\n'); + es_putc ('m', fp); + es_putc (':', fp); + es_putc ('\n', fp); } } } + static void -show_names (KBNODE keyblock, PKT_public_key * pk, unsigned int flag, +show_names (estream_t fp, + KBNODE keyblock, PKT_public_key * pk, unsigned int flag, int with_prefs) { KBNODE node; @@ -2645,18 +2653,18 @@ show_names (KBNODE keyblock, PKT_public_key * pk, unsigned int flag, if (!flag || (flag && (node->flag & flag))) { if (!(flag & NODFLG_MARK_A) && pk) - tty_printf ("%s ", uid_trust_string_fixed (pk, uid)); + tty_fprintf (fp, "%s ", uid_trust_string_fixed (pk, uid)); if (flag & NODFLG_MARK_A) - tty_printf (" "); + tty_fprintf (fp, " "); else if (node->flag & NODFLG_SELUID) - tty_printf ("(%d)* ", i); + tty_fprintf (fp, "(%d)* ", i); else if (uid->is_primary) - tty_printf ("(%d). ", i); + tty_fprintf (fp, "(%d). ", i); else - tty_printf ("(%d) ", i); - tty_print_utf8_string (uid->name, uid->len); - tty_printf ("\n"); + tty_fprintf (fp, "(%d) ", i); + tty_print_utf8_string2 (fp, uid->name, uid->len, 0); + tty_fprintf (fp, "\n"); if (with_prefs && pk) { if (pk->version > 3 || uid->selfsigversion > 3) @@ -2679,8 +2687,8 @@ show_names (KBNODE keyblock, PKT_public_key * pk, unsigned int flag, show_prefs (uid, selfsig, with_prefs == 2); } else - tty_printf (_("There are no preferences on a" - " PGP 2.x-style user ID.\n")); + tty_fprintf (fp, _("There are no preferences on a" + " PGP 2.x-style user ID.\n")); } } } @@ -2689,11 +2697,14 @@ show_names (KBNODE keyblock, PKT_public_key * pk, unsigned int flag, /* - * Display the key a the user ids, if only_marked is true, do only - * so for user ids with mark A flag set and dont display the index number + * Display the key a the user ids, if only_marked is true, do only so + * for user ids with mark A flag set and do not display the index + * number. If FP is not NULL print to the given stream and not to the + * tty (ignored in with-colons mode). */ static void -show_key_with_all_names (KBNODE keyblock, int only_marked, int with_revoker, +show_key_with_all_names (estream_t fp, + KBNODE keyblock, int only_marked, int with_revoker, int with_fpr, int with_subkeys, int with_prefs) { KBNODE node; @@ -2704,7 +2715,7 @@ show_key_with_all_names (KBNODE keyblock, int only_marked, int with_revoker, if (opt.with_colons) { - show_key_with_all_names_colon (keyblock); + show_key_with_all_names_colon (fp, keyblock); return; } @@ -2716,7 +2727,8 @@ show_key_with_all_names (KBNODE keyblock, int only_marked, int with_revoker, && !is_deleted_kbnode (node))) { PKT_public_key *pk = node->pkt->pkt.public_key; - const char *otrust = "err", *trust = "err"; + const char *otrust = "err"; + const char *trust = "err"; if (node->pkt->pkttype == PKT_PUBLIC_KEY) { @@ -2741,7 +2753,8 @@ show_key_with_all_names (KBNODE keyblock, int only_marked, int with_revoker, if (pk->flags.revoked) { char *user = get_user_id_string_native (pk->revoked.keyid); - tty_printf (_("The following key was revoked on" + tty_fprintf (fp, + _("The following key was revoked on" " %s by %s key %s\n"), revokestr_from_pk (pk), gcry_pk_algo_name (pk->revoked.algo), user); @@ -2764,22 +2777,23 @@ show_key_with_all_names (KBNODE keyblock, int only_marked, int with_revoker, MAX_FINGERPRINT_LEN, r_keyid); user = get_user_id_string_native (r_keyid); - tty_printf (_("This key may be revoked by %s key %s"), - algo ? algo : "?", user); + tty_fprintf (fp, + _("This key may be revoked by %s key %s"), + algo ? algo : "?", user); if (pk->revkey[i].class & 0x40) { - tty_printf (" "); - tty_printf (_("(sensitive)")); + tty_fprintf (fp, " "); + tty_fprintf (fp, _("(sensitive)")); } - tty_printf ("\n"); + tty_fprintf (fp, "\n"); xfree (user); } } keyid_from_pk (pk, NULL); - tty_printf ("%s%c %s/%s", + tty_fprintf (fp, "%s%c %s/%s", node->pkt->pkttype == PKT_PUBLIC_KEY ? "pub" : node->pkt->pkttype == PKT_PUBLIC_SUBKEY ? "sub" : node->pkt->pkttype == PKT_SECRET_KEY ? "sec" : "ssb", @@ -2788,28 +2802,28 @@ show_key_with_all_names (KBNODE keyblock, int only_marked, int with_revoker, keystr (pk->keyid)); if (opt.legacy_list_mode) - tty_printf (" "); + tty_fprintf (fp, " "); else - tty_printf ("\n "); + tty_fprintf (fp, "\n "); - tty_printf (_("created: %s"), datestr_from_pk (pk)); - tty_printf (" "); + tty_fprintf (fp, _("created: %s"), datestr_from_pk (pk)); + tty_fprintf (fp, " "); if (pk->flags.revoked) - tty_printf (_("revoked: %s"), revokestr_from_pk (pk)); + tty_fprintf (fp, _("revoked: %s"), revokestr_from_pk (pk)); else if (pk->has_expired) - tty_printf (_("expired: %s"), expirestr_from_pk (pk)); + tty_fprintf (fp, _("expired: %s"), expirestr_from_pk (pk)); else - tty_printf (_("expires: %s"), expirestr_from_pk (pk)); - tty_printf (" "); - tty_printf (_("usage: %s"), usagestr_from_pk (pk)); - tty_printf ("\n"); + tty_fprintf (fp, _("expires: %s"), expirestr_from_pk (pk)); + tty_fprintf (fp, " "); + tty_fprintf (fp, _("usage: %s"), usagestr_from_pk (pk)); + tty_fprintf (fp, "\n"); if (pk->seckey_info && pk->seckey_info->is_protected && pk->seckey_info->s2k.mode == 1002) { - tty_printf ("%*s%s", opt.legacy_list_mode? 21:5, "", - _("card-no: ")); + tty_fprintf (fp, "%*s%s", opt.legacy_list_mode? 21:5, "", + _("card-no: ")); if (pk->seckey_info->ivlen == 16 && !memcmp (pk->seckey_info->iv, "\xD2\x76\x00\x01\x24\x01", 6)) @@ -2818,17 +2832,17 @@ show_key_with_all_names (KBNODE keyblock, int only_marked, int with_revoker, for (i = 8; i < 14; i++) { if (i == 10) - tty_printf (" "); - tty_printf ("%02X", pk->seckey_info->iv[i]); + tty_fprintf (fp, " "); + tty_fprintf (fp, "%02X", pk->seckey_info->iv[i]); } } else { /* Unknown card: Print all. */ for (i = 0; i < pk->seckey_info->ivlen; i++) - tty_printf ("%02X", pk->seckey_info->iv[i]); + tty_fprintf (fp, "%02X", pk->seckey_info->iv[i]); } - tty_printf ("\n"); + tty_fprintf (fp, "\n"); } if (node->pkt->pkttype == PKT_PUBLIC_KEY @@ -2836,9 +2850,9 @@ show_key_with_all_names (KBNODE keyblock, int only_marked, int with_revoker, { if (opt.trust_model != TM_ALWAYS) { - tty_printf ("%*s", - opt.legacy_list_mode? - ((int) keystrlen () + 13):5, ""); + tty_fprintf (fp, "%*s", + opt.legacy_list_mode? + ((int) keystrlen () + 13):5, ""); /* Ownertrust is only meaningful for the PGP or classic trust models */ if (opt.trust_model == TM_PGP @@ -2847,37 +2861,38 @@ show_key_with_all_names (KBNODE keyblock, int only_marked, int with_revoker, int width = 14 - strlen (otrust); if (width <= 0) width = 1; - tty_printf (_("trust: %s"), otrust); - tty_printf ("%*s", width, ""); + tty_fprintf (fp, _("trust: %s"), otrust); + tty_fprintf (fp, "%*s", width, ""); } - tty_printf (_("validity: %s"), trust); - tty_printf ("\n"); + tty_fprintf (fp, _("validity: %s"), trust); + tty_fprintf (fp, "\n"); } if (node->pkt->pkttype == PKT_PUBLIC_KEY && (get_ownertrust (pk) & TRUST_FLAG_DISABLED)) { - tty_printf ("*** "); - tty_printf (_("This key has been disabled")); - tty_printf ("\n"); + tty_fprintf (fp, "*** "); + tty_fprintf (fp, _("This key has been disabled")); + tty_fprintf (fp, "\n"); } } if ((node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_SECRET_KEY) && with_fpr) { - print_fingerprint (pk, 2); - tty_printf ("\n"); + print_fingerprint (fp, pk, 2); + tty_fprintf (fp, "\n"); } } } - show_names (keyblock, primary, only_marked ? NODFLG_MARK_A : 0, with_prefs); + show_names (fp, + keyblock, primary, only_marked ? NODFLG_MARK_A : 0, with_prefs); if (do_warn) - tty_printf (_("Please note that the shown key validity" - " is not necessarily correct\n" - "unless you restart the program.\n")); + tty_fprintf (fp, _("Please note that the shown key validity" + " is not necessarily correct\n" + "unless you restart the program.\n")); } @@ -2912,7 +2927,7 @@ show_basic_key_info (KBNODE keyblock) tty_printf (" "); tty_printf (_("expires: %s"), expirestr_from_pk (pk)); tty_printf ("\n"); - print_fingerprint (pk, 3); + print_fingerprint (NULL, pk, 3); tty_printf ("\n"); } } @@ -2962,7 +2977,7 @@ show_key_and_fingerprint (KBNODE keyblock) } tty_printf ("\n"); if (pk) - print_fingerprint (pk, 2); + print_fingerprint (NULL, pk, 2); } @@ -3438,7 +3453,7 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive) } print_pubkey_info (NULL, revoker_pk); - print_fingerprint (revoker_pk, 2); + print_fingerprint (NULL, revoker_pk, 2); tty_printf ("\n"); tty_printf (_("WARNING: appointing a key as a designated revoker " diff --git a/g10/keylist.c b/g10/keylist.c index 6e5ebda..71f72e2 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -866,7 +866,7 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque) es_fprintf (es_stdout, "\n"); if (fpr) - print_fingerprint (pk, 0); + print_fingerprint (NULL, pk, 0); if (opt.with_keygrip && hexgrip) es_fprintf (es_stdout, " Keygrip = %s\n", hexgrip); @@ -991,7 +991,7 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque) es_putc ('\n', es_stdout); if (fpr > 1) { - print_fingerprint (pk2, 0); + print_fingerprint (NULL, pk2, 0); if (serialno) print_card_serialno (serialno); } @@ -1112,7 +1112,7 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque) } void -print_revokers (PKT_public_key * pk) +print_revokers (estream_t fp, PKT_public_key * pk) { /* print the revoker record */ if (!pk->revkey && pk->numrevkeys) @@ -1125,12 +1125,13 @@ print_revokers (PKT_public_key * pk) { byte *p; - es_fprintf (es_stdout, "rvk:::%d::::::", pk->revkey[i].algid); + es_fprintf (fp, "rvk:::%d::::::", pk->revkey[i].algid); p = pk->revkey[i].fpr; for (j = 0; j < 20; j++, p++) - es_fprintf (es_stdout, "%02X", *p); - es_fprintf (es_stdout, ":%02x%s:\n", pk->revkey[i].class, - (pk->revkey[i].class & 0x40) ? "s" : ""); + es_fprintf (fp, "%02X", *p); + es_fprintf (fp, ":%02x%s:\n", + pk->revkey[i].class, + (pk->revkey[i].class & 0x40) ? "s" : ""); } } } @@ -1227,9 +1228,9 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr) es_putc (':', es_stdout); /* End of field 17. */ es_putc ('\n', es_stdout); - print_revokers (pk); + print_revokers (es_stdout, pk); if (fpr) - print_fingerprint (pk, 0); + print_fingerprint (NULL, pk, 0); if (opt.with_key_data || opt.with_keygrip) { if (hexgrip) @@ -1353,7 +1354,7 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr) es_putc (':', es_stdout); /* End of field 17. */ es_putc ('\n', es_stdout); if (fpr > 1) - print_fingerprint (pk2, 0); + print_fingerprint (NULL, pk2, 0); if (opt.with_key_data || opt.with_keygrip) { if (hexgrip) @@ -1553,10 +1554,12 @@ list_keyblock (KBNODE keyblock, int secret, int fpr, void *opaque) * 3: direct use of tty but only primary key. * * Modes 1 and 2 will try and print both subkey and primary key - * fingerprints. A MODE with bit 7 set is used internally. + * fingerprints. A MODE with bit 7 set is used internally. If + * OVERRIDE_FP is not NULL that stream will be used in 0 instead + * of es_stdout or instead of the TTY in modes 2 and 3. */ void -print_fingerprint (PKT_public_key *pk, int mode) +print_fingerprint (estream_t override_fp, PKT_public_key *pk, int mode) { byte array[MAX_FINGERPRINT_LEN], *p; size_t i, n; @@ -1581,7 +1584,7 @@ print_fingerprint (PKT_public_key *pk, int mode) { PKT_public_key *primary_pk = xmalloc_clear (sizeof (*primary_pk)); get_pubkey (primary_pk, pk->main_keyid); - print_fingerprint (primary_pk, mode | 0x80); + print_fingerprint (override_fp, primary_pk, (mode | 0x80)); free_public_key (primary_pk); } @@ -1595,7 +1598,7 @@ print_fingerprint (PKT_public_key *pk, int mode) } else if (mode == 2) { - fp = NULL; /* Use tty. */ + fp = override_fp; /* Use tty or given stream. */ if (primary) /* TRANSLATORS: this should fit into 24 bytes to that the * fingerprint data is properly aligned with the user ID */ @@ -1605,12 +1608,12 @@ print_fingerprint (PKT_public_key *pk, int mode) } else if (mode == 3) { - fp = NULL; /* Use tty. */ + fp = override_fp; /* Use tty or given stream. */ text = _(" Key fingerprint ="); } else { - fp = es_stdout; + fp = override_fp? override_fp : es_stdout; text = _(" Key fingerprint ="); } diff --git a/g10/main.h b/g10/main.h index 28115ca..ad1a9f6 100644 --- a/g10/main.h +++ b/g10/main.h @@ -325,8 +325,8 @@ void secret_key_list (ctrl_t ctrl, strlist_t list ); void print_subpackets_colon(PKT_signature *sig); void reorder_keyblock (KBNODE keyblock); void list_keyblock( KBNODE keyblock, int secret, int fpr, void *opaque ); -void print_fingerprint (PKT_public_key *pk, int mode); -void print_revokers(PKT_public_key *pk); +void print_fingerprint (estream_t fp, PKT_public_key *pk, int mode); +void print_revokers (estream_t fp, PKT_public_key *pk); void show_policy_url(PKT_signature *sig,int indent,int mode); void show_keyserver_url(PKT_signature *sig,int indent,int mode); void show_notation(PKT_signature *sig,int indent,int mode,int which); diff --git a/g10/mainproc.c b/g10/mainproc.c index 6bd475b..f830eee 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -953,7 +953,7 @@ list_node( CTX c, KBNODE node ) if( node->next && node->next->pkt->pkttype == PKT_RING_TRUST) { putchar('\n'); any=1; if( opt.fingerprint ) - print_fingerprint (pk, 0); + print_fingerprint (NULL, pk, 0); printf("rtv:1:%u:\n", node->next->pkt->pkt.ring_trust->trustval ); } @@ -991,7 +991,7 @@ list_node( CTX c, KBNODE node ) putchar(':'); putchar('\n'); if( opt.fingerprint && !any ) - print_fingerprint ( pk, 0 ); + print_fingerprint (NULL, pk, 0 ); if( opt.with_colons && node->next && node->next->pkt->pkttype == PKT_RING_TRUST ) { @@ -1030,7 +1030,7 @@ list_node( CTX c, KBNODE node ) if( !any ) putchar('\n'); if( !mainkey && opt.fingerprint > 1 ) - print_fingerprint( pk, 0 ); + print_fingerprint (NULL, pk, 0); } else if( (mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) ) || node->pkt->pkttype == PKT_SECRET_SUBKEY ) { diff --git a/g10/pkclist.c b/g10/pkclist.c index a6d687a..49cd309 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -258,7 +258,7 @@ do_edit_ownertrust (PKT_public_key *pk, int mode, tty_printf(_(" aka \"%s\"\n"),p); } - print_fingerprint (pk, 2); + print_fingerprint (NULL, pk, 2); tty_printf("\n"); release_kbnode (keyblock); } @@ -470,7 +470,7 @@ do_we_trust_pre( PKT_public_key *pk, unsigned int trustlevel ) if( !opt.batch && !rc ) { print_pubkey_info(NULL,pk); - print_fingerprint (pk, 2); + print_fingerprint (NULL, pk, 2); tty_printf("\n"); tty_printf( @@ -529,7 +529,7 @@ check_signatures_trust( PKT_signature *sig ) if( !opt.quiet ) log_info(_("WARNING: Using untrusted key!\n")); if (opt.with_fingerprint) - print_fingerprint (pk, 1); + print_fingerprint (NULL, pk, 1); goto leave; } @@ -617,7 +617,7 @@ check_signatures_trust( PKT_signature *sig ) { case TRUST_EXPIRED: log_info(_("Note: This key has expired!\n")); - print_fingerprint (pk, 1); + print_fingerprint (NULL, pk, 1); break; default: @@ -631,7 +631,7 @@ check_signatures_trust( PKT_signature *sig ) " a trusted signature!\n")); log_info(_(" There is no indication that the " "signature belongs to the owner.\n" )); - print_fingerprint (pk, 1); + print_fingerprint (NULL, pk, 1); break; case TRUST_NEVER: @@ -640,7 +640,7 @@ check_signatures_trust( PKT_signature *sig ) log_info(_("WARNING: We do NOT trust this key!\n")); log_info(_(" The signature is probably a FORGERY.\n")); if (opt.with_fingerprint) - print_fingerprint (pk, 1); + print_fingerprint (NULL, pk, 1); rc = gpg_error (GPG_ERR_BAD_SIGNATURE); break; @@ -650,19 +650,19 @@ check_signatures_trust( PKT_signature *sig ) " sufficiently trusted signatures!\n")); log_info(_(" It is not certain that the" " signature belongs to the owner.\n" )); - print_fingerprint (pk, 1); + print_fingerprint (NULL, pk, 1); break; case TRUST_FULLY: write_status( STATUS_TRUST_FULLY ); if (opt.with_fingerprint) - print_fingerprint (pk, 1); + print_fingerprint (NULL, pk, 1); break; case TRUST_ULTIMATE: write_status( STATUS_TRUST_ULTIMATE ); if (opt.with_fingerprint) - print_fingerprint (pk, 1); + print_fingerprint (NULL, pk, 1); break; } commit 5c2a50cdc90e85b1fc380851ccfbe9186969b658 Author: Werner Koch Date: Sun Mar 23 13:42:53 2014 +0100 agent: Replace es_mopen by es_fopenmem for ssh. * agent/command-ssh.c (ssh_read_key_public_from_blob): Use es_fopenmem. (ssh_handler_request_identities): Ditto. (ssh_request_process): Ditto. -- es_fopenmem is easier to understand than the more general function es_mopen. Thus we better use the former for clarity. diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 5d7186f..04fe049 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -2368,13 +2368,11 @@ ssh_read_key_public_from_blob (unsigned char *blob, size_t blob_size, gcry_sexp_t *key_public, ssh_key_type_spec_t *key_spec) { - estream_t blob_stream; gpg_error_t err; + estream_t blob_stream; - err = 0; - /* FIXME: Use fopenmem_init */ - blob_stream = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+"); - if (! blob_stream) + blob_stream = es_fopenmem (0, "r+b"); + if (!blob_stream) { err = gpg_error_from_syserror (); goto out; @@ -2391,10 +2389,7 @@ ssh_read_key_public_from_blob (unsigned char *blob, size_t blob_size, err = ssh_receive_key (blob_stream, key_public, 0, 0, key_spec); out: - - if (blob_stream) - es_fclose (blob_stream); - + es_fclose (blob_stream); return err; } @@ -2619,7 +2614,7 @@ ssh_handler_request_identities (ctrl_t ctrl, key_counter = 0; err = 0; - key_blobs = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+b"); + key_blobs = es_fopenmem (0, "r+b"); if (! key_blobs) { err = gpg_error_from_syserror (); @@ -3447,21 +3442,16 @@ static int ssh_request_process (ctrl_t ctrl, estream_t stream_sock) { ssh_request_spec_t *spec; - estream_t response; - estream_t request; + estream_t response = NULL; + estream_t request = NULL; unsigned char request_type; gpg_error_t err; - int send_err; + int send_err = 0; int ret; - unsigned char *request_data; + unsigned char *request_data = NULL; u32 request_data_size; u32 response_size; - request_data = NULL; - response = NULL; - request = NULL; - send_err = 0; - /* Create memory streams for request/response data. The entire request will be stored in secure memory, since it might contain secret key material. The response does not have to be stored in @@ -3500,9 +3490,9 @@ ssh_request_process (ctrl_t ctrl, estream_t stream_sock) } if (spec->secret_input) - request = es_mopen (NULL, 0, 0, 1, realloc_secure, gcry_free, "r+"); + request = es_mopen (NULL, 0, 0, 1, realloc_secure, gcry_free, "r+b"); else - request = es_mopen (NULL, 0, 0, 1, gcry_realloc, gcry_free, "r+"); + request = es_mopen (NULL, 0, 0, 1, gcry_realloc, gcry_free, "r+b"); if (! request) { err = gpg_error_from_syserror (); @@ -3519,7 +3509,7 @@ ssh_request_process (ctrl_t ctrl, estream_t stream_sock) goto out; es_rewind (request); - response = es_mopen (NULL, 0, 0, 1, NULL, NULL, "r+"); + response = es_fopenmem (0, "r+b"); if (! response) { err = gpg_error_from_syserror (); @@ -3595,11 +3585,9 @@ ssh_request_process (ctrl_t ctrl, estream_t stream_sock) leave: - if (request) - es_fclose (request); - if (response) - es_fclose (response); - xfree (request_data); /* FIXME? */ + es_fclose (request); + es_fclose (response); + xfree (request_data); return !!err; } ----------------------------------------------------------------------- Summary of changes: agent/command-ssh.c | 42 ++-- common/ttyio.c | 115 +++++++--- common/ttyio.h | 5 +- doc/gpg.texi | 18 ++ g10/card-util.c | 6 +- g10/gpg.c | 25 +++ g10/keyedit.c | 619 +++++++++++++++++++++++++++++++++------------------ g10/keylist.c | 35 +-- g10/main.h | 6 +- g10/mainproc.c | 6 +- g10/pkclist.c | 18 +- 11 files changed, 587 insertions(+), 308 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org