diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/Makefile.am | 3 | ||||
-rw-r--r-- | common/argparse.c | 37 | ||||
-rw-r--r-- | common/argparse.h | 36 | ||||
-rw-r--r-- | common/asshelp.c | 119 | ||||
-rw-r--r-- | common/exechelp-posix.c | 55 | ||||
-rw-r--r-- | common/exechelp-w32.c | 5 | ||||
-rw-r--r-- | common/exechelp-w32ce.c | 5 | ||||
-rw-r--r-- | common/exechelp.h | 2 | ||||
-rw-r--r-- | common/iobuf.c | 122 | ||||
-rw-r--r-- | common/iobuf.h | 6 | ||||
-rw-r--r-- | common/logging.c | 40 | ||||
-rw-r--r-- | common/logging.h | 51 | ||||
-rw-r--r-- | common/miscellaneous.c | 16 | ||||
-rw-r--r-- | common/openpgpdefs.h | 14 | ||||
-rw-r--r-- | common/pkscreening.c | 159 | ||||
-rw-r--r-- | common/pkscreening.h | 26 | ||||
-rw-r--r-- | common/sysutils.c | 7 | ||||
-rw-r--r-- | common/util.h | 5 |
18 files changed, 518 insertions, 190 deletions
diff --git a/common/Makefile.am b/common/Makefile.am index fcbe7ea66..94318dae4 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -94,7 +94,8 @@ common_sources = \ name-value.c name-value.h \ recsel.c recsel.h \ ksba-io-support.c ksba-io-support.h \ - compliance.c compliance.h + compliance.c compliance.h \ + pkscreening.c pkscreening.h if HAVE_W32_SYSTEM diff --git a/common/argparse.c b/common/argparse.c index 90d0ff7f3..331998bb2 100644 --- a/common/argparse.c +++ b/common/argparse.c @@ -1,32 +1,23 @@ -/* [argparse.c wk 17.06.97] Argument Parser for option handling - * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc. +/* argparse.c - Argument Parser for option handling * Copyright (C) 1997-2001, 2006-2008, 2013-2017 Werner Koch + * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc. + * Copyright (C) 2015-2017 g10 Code GmbH * * This file is part of GnuPG. * - * GnuPG is free software; you can redistribute and/or modify this - * part of GnuPG under the terms of either - * - * - the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at - * your option) any later version. - * - * or - * - * - the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * or both in parallel, as here. + * This file 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. * - * 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. + * This file 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 copies of the GNU General Public License - * and the GNU Lesser General Public License along with this program; - * if not, see <https://gnu.org/licenses/>. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: LGPL-2.1+ */ /* This file may be used as part of GnuPG or standalone. A GnuPG diff --git a/common/argparse.h b/common/argparse.h index cdd18d9a2..4167d667a 100644 --- a/common/argparse.h +++ b/common/argparse.h @@ -1,31 +1,23 @@ /* argparse.h - Argument parser for option handling. - * Copyright (C) 1998,1999,2000,2001,2006 Free Software Foundation, Inc. + * Copyright (C) 1997-2001, 2006-2008, 2013-2017 Werner Koch + * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc. + * Copyright (C) 2015-2017 g10 Code GmbH * * This file is part of GnuPG. * - * GnuPG is free software; you can redistribute and/or modify this - * part of GnuPG under the terms of either + * This file 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. * - * - the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at - * your option) any later version. + * This file 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. * - * or - * - * - the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * or both in parallel, as here. - * - * 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 copies of the GNU General Public License - * and the GNU Lesser General Public License along with this program; - * if not, see <https://www.gnu.org/licenses/>. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: LGPL-2.1+ */ #ifndef GNUPG_COMMON_ARGPARSE_H diff --git a/common/asshelp.c b/common/asshelp.c index f3a92f9e5..5209ea6cf 100644 --- a/common/asshelp.c +++ b/common/asshelp.c @@ -93,7 +93,7 @@ my_libassuan_log_handler (assuan_context_t ctx, void *hook, return 0; /* Temporary disabled. */ if (msg) - log_string (GPGRT_LOG_DEBUG, msg); + log_string (GPGRT_LOGLVL_DEBUG, msg); return 1; } @@ -307,6 +307,71 @@ unlock_spawning (lock_spawn_t *lock, const char *name) } } + +/* Helper for start_new_gpg_agent and start_new_dirmngr. + * Values for WHICH are: + * 0 - Start gpg-agent + * 1 - Start dirmngr + * SECS give the number of seconds to wait. SOCKNAME is the name of + * the socket to connect. VERBOSE is the usual verbose flag. CTX is + * the assuan context. DID_SUCCESS_MSG will be set to 1 if a success + * messages has been printed. + */ +static gpg_error_t +wait_for_sock (int secs, int which, const char *sockname, + int verbose, assuan_context_t ctx, int *did_success_msg) +{ + gpg_error_t err = 0; + int target_us = secs * 1000000; + int elapsed_us = 0; + /* + * 977us * 1024 = just a little more than 1s. + * so we will double this timeout 10 times in the first + * second, and then switch over to 1s checkins. + */ + int next_sleep_us = 977; + int lastalert = secs+1; + int secsleft; + + while (elapsed_us < target_us) + { + if (verbose) + { + secsleft = (target_us - elapsed_us + 999999)/1000000; + /* log_clock ("left=%d last=%d targ=%d elap=%d next=%d\n", */ + /* secsleft, lastalert, target_us, elapsed_us, */ + /* next_sleep_us); */ + if (secsleft < lastalert) + { + log_info (which == 1? + _("waiting for the dirmngr to come up ... (%ds)\n"): + _("waiting for the agent to come up ... (%ds)\n"), + secsleft); + lastalert = secsleft; + } + } + gnupg_usleep (next_sleep_us); + elapsed_us += next_sleep_us; + err = assuan_socket_connect (ctx, sockname, 0, 0); + if (!err) + { + if (verbose) + { + log_info (which == 1? + _("connection to the dirmngr established\n"): + _("connection to the agent established\n")); + *did_success_msg = 1; + } + break; + } + next_sleep_us *= 2; + if (next_sleep_us > 1000000) + next_sleep_us = 1000000; + } + return err; +} + + /* Try to connect to the agent via socket or start it if it is not running and AUTOSTART is set. Handle the server's initial greeting. Returns a new assuan context at R_CTX or an error @@ -433,25 +498,8 @@ start_new_gpg_agent (assuan_context_t *r_ctx, log_error ("failed to start agent '%s': %s\n", agent_program, gpg_strerror (err)); else - { - for (i=0; i < SECS_TO_WAIT_FOR_AGENT; i++) - { - if (verbose) - log_info (_("waiting for the agent to come up ... (%ds)\n"), - SECS_TO_WAIT_FOR_AGENT - i); - gnupg_sleep (1); - err = assuan_socket_connect (ctx, sockname, 0, 0); - if (!err) - { - if (verbose) - { - log_info (_("connection to agent established\n")); - did_success_msg = 1; - } - break; - } - } - } + err = wait_for_sock (SECS_TO_WAIT_FOR_AGENT, 0, + sockname, verbose, ctx, &did_success_msg); } unlock_spawning (&lock, "agent"); @@ -468,7 +516,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx, } if (debug && !did_success_msg) - log_debug ("connection to agent established\n"); + log_debug ("connection to the agent established\n"); err = assuan_transact (ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL); @@ -485,7 +533,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx, NULL, NULL, NULL, NULL, NULL, NULL)) { if (verbose) - log_info (_("connection to agent is in restricted mode\n")); + log_info (_("connection to the agent is in restricted mode\n")); err = 0; } } @@ -542,7 +590,7 @@ start_new_dirmngr (assuan_context_t *r_ctx, dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR); if (verbose) - log_info (_("no running Dirmngr - starting '%s'\n"), + log_info (_("no running dirmngr - starting '%s'\n"), dirmngr_program); if (status_cb) @@ -584,29 +632,8 @@ start_new_dirmngr (assuan_context_t *r_ctx, log_error ("failed to start the dirmngr '%s': %s\n", dirmngr_program, gpg_strerror (err)); else - { - int i; - - for (i=0; i < SECS_TO_WAIT_FOR_DIRMNGR; i++) - { - if (verbose) - log_info (_("waiting for the dirmngr " - "to come up ... (%ds)\n"), - SECS_TO_WAIT_FOR_DIRMNGR - i); - gnupg_sleep (1); - err = assuan_socket_connect (ctx, sockname, 0, 0); - if (!err) - { - if (verbose) - { - log_info (_("connection to the dirmngr" - " established\n")); - did_success_msg = 1; - } - break; - } - } - } + err = wait_for_sock (SECS_TO_WAIT_FOR_DIRMNGR, 1, + sockname, verbose, ctx, &did_success_msg); } unlock_spawning (&lock, "dirmngr"); diff --git a/common/exechelp-posix.c b/common/exechelp-posix.c index 7237993a2..425f2b4d5 100644 --- a/common/exechelp-posix.c +++ b/common/exechelp-posix.c @@ -1,6 +1,6 @@ /* exechelp.c - Fork and exec helpers for POSIX - * Copyright (C) 2004, 2007, 2008, 2009, - * 2010 Free Software Foundation, Inc. + * Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc. + * Copyright (C) 2004, 2006-2012, 2014-2017 g10 Code GmbH * * This file is part of GnuPG. * @@ -26,6 +26,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: (LGPL-3.0+ OR GPL-2.0+) */ #include <config.h> @@ -784,30 +785,32 @@ gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count, } } - if (ec == 0) - for (i = 0; i < count; i++) - { - if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i]) == 127) - { - log_error (_("error running '%s': probably not installed\n"), - pgmnames[i]); - ec = GPG_ERR_CONFIGURATION; - } - else if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i])) - { - if (dummy) - log_error (_("error running '%s': exit status %d\n"), - pgmnames[i], WEXITSTATUS (r_exitcodes[i])); - else - r_exitcodes[i] = WEXITSTATUS (r_exitcodes[i]); - ec = GPG_ERR_GENERAL; - } - else if (!WIFEXITED (r_exitcodes[i])) - { - log_error (_("error running '%s': terminated\n"), pgmnames[i]); - ec = GPG_ERR_GENERAL; - } - } + for (i = 0; i < count; i++) + { + if (r_exitcodes[i] == -1) + continue; + + if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i]) == 127) + { + log_error (_("error running '%s': probably not installed\n"), + pgmnames[i]); + ec = GPG_ERR_CONFIGURATION; + } + else if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i])) + { + if (dummy) + log_error (_("error running '%s': exit status %d\n"), + pgmnames[i], WEXITSTATUS (r_exitcodes[i])); + else + r_exitcodes[i] = WEXITSTATUS (r_exitcodes[i]); + ec = GPG_ERR_GENERAL; + } + else if (!WIFEXITED (r_exitcodes[i])) + { + log_error (_("error running '%s': terminated\n"), pgmnames[i]); + ec = GPG_ERR_GENERAL; + } + } xfree (dummy); return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec); diff --git a/common/exechelp-w32.c b/common/exechelp-w32.c index da174508e..86b1d6869 100644 --- a/common/exechelp-w32.c +++ b/common/exechelp-w32.c @@ -1,6 +1,6 @@ /* exechelp-w32.c - Fork and exec helpers for W32. - * Copyright (C) 2004, 2007, 2008, 2009, - * 2010 Free Software Foundation, Inc. + * Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc. + * Copyright (C) 2004, 2006-2012, 2014-2017 g10 Code GmbH * * This file is part of GnuPG. * @@ -26,6 +26,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: (LGPL-3.0+ OR GPL-2.0+) */ #include <config.h> diff --git a/common/exechelp-w32ce.c b/common/exechelp-w32ce.c index ec9f01441..3d68a01d1 100644 --- a/common/exechelp-w32ce.c +++ b/common/exechelp-w32ce.c @@ -1,6 +1,6 @@ /* exechelp-w32.c - Fork and exec helpers for W32CE. - * Copyright (C) 2004, 2007, 2008, 2009, - * 2010 Free Software Foundation, Inc. + * Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc. + * Copyright (C) 2010-2012, 2014-2016 g10 Code GmbH * * This file is part of GnuPG. * @@ -26,6 +26,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: (LGPL-3.0+ OR GPL-2.0+) */ #include <config.h> diff --git a/common/exechelp.h b/common/exechelp.h index 2b40ba098..9e1f56f70 100644 --- a/common/exechelp.h +++ b/common/exechelp.h @@ -1,5 +1,6 @@ /* exechelp.h - Definitions for the fork and exec helpers * Copyright (C) 2004, 2009, 2010 Free Software Foundation, Inc. + * Copyright (C) 2004, 2006-2012, 2014-2017 g10 Code GmbH * * This file is part of GnuPG. * @@ -25,6 +26,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: (LGPL-3.0+ OR GPL-2.0+) */ #ifndef GNUPG_COMMON_EXECHELP_H diff --git a/common/iobuf.c b/common/iobuf.c index 5a9fd7caf..02c9b491c 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -59,10 +59,8 @@ /*-- Begin configurable part. --*/ -/* The size of the internal buffers. - NOTE: If you change this value you MUST also adjust the regression - test "armored_key_8192" in armor.test! */ -#define IOBUF_BUFFER_SIZE 8192 +/* The standard size of the internal buffers. */ +#define DEFAULT_IOBUF_BUFFER_SIZE (64*1024) /* To avoid a potential DoS with compression packets we better limit the number of filters in a chain. */ @@ -70,6 +68,10 @@ /*-- End configurable part. --*/ +/* The size of the iobuffers. This can be chnages using the + * iobuf_set_buffer_size fucntion. */ +static unsigned int iobuf_buffer_size = DEFAULT_IOBUF_BUFFER_SIZE; + #ifdef HAVE_W32_SYSTEM # ifdef HAVE_W32CE_SYSTEM @@ -92,6 +94,7 @@ typedef struct int keep_open; int no_cache; int eof_seen; + int delayed_rc; int print_only_name; /* Flags indicating that fname is not a real file. */ char fname[1]; /* Name of the file. */ } file_filter_ctx_t; @@ -167,7 +170,7 @@ static int translate_file_handle (int fd, int for_write); to be sent to A's filter function. If A is a IOBUF_OUTPUT_TEMP filter, then this also enlarges the - buffer by IOBUF_BUFFER_SIZE. + buffer by iobuf_buffer_size. May only be called on an IOBUF_OUTPUT or IOBUF_OUTPUT_TEMP filters. */ static int filter_flush (iobuf_t a); @@ -451,12 +454,20 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, if (control == IOBUFCTRL_UNDERFLOW) { - assert (size); /* We need a buffer. */ + log_assert (size); /* We need a buffer. */ if (a->eof_seen) { rc = -1; *ret_len = 0; } + else if (a->delayed_rc) + { + rc = a->delayed_rc; + a->delayed_rc = 0; + if (rc == -1) + a->eof_seen = -1; + *ret_len = 0; + } else { #ifdef HAVE_W32_SYSTEM @@ -487,29 +498,39 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, int n; nbytes = 0; - do - { - n = read (f, buf, size); - } - while (n == -1 && errno == EINTR); - if (n == -1) - { /* error */ - if (errno != EPIPE) - { - rc = gpg_error_from_syserror (); - log_error ("%s: read error: %s\n", - a->fname, strerror (errno)); - } - } - else if (!n) - { /* eof */ - a->eof_seen = 1; - rc = -1; - } - else - { - nbytes = n; - } + read_more: + do + { + n = read (f, buf + nbytes, size - nbytes); + } + while (n == -1 && errno == EINTR); + if (n > 0) + { + nbytes += n; + if (nbytes < size) + goto read_more; + } + else if (!n) /* eof */ + { + if (nbytes) + a->delayed_rc = -1; + else + { + a->eof_seen = 1; + rc = -1; + } + } + else /* error */ + { + rc = gpg_error_from_syserror (); + if (gpg_err_code (rc) != GPG_ERR_EPIPE) + log_error ("%s: read error: %s\n", a->fname, gpg_strerror (rc)); + if (nbytes) + { + a->delayed_rc = rc; + rc = 0; + } + } #endif *ret_len = nbytes; } @@ -569,6 +590,7 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, else if (control == IOBUFCTRL_INIT) { a->eof_seen = 0; + a->delayed_rc = 0; a->keep_open = 0; a->no_cache = 0; } @@ -1053,6 +1075,30 @@ block_filter (void *opaque, int control, iobuf_t chain, byte * buffer, return rc; } + +/* Change the default size for all IOBUFs to KILOBYTE. This needs to + * be called before any iobufs are used and can only be used once. + * Returns the current value. Using 0 has no effect except for + * returning the current value. */ +unsigned int +iobuf_set_buffer_size (unsigned int kilobyte) +{ + static int used; + + if (!used && kilobyte) + { + if (kilobyte < 4) + kilobyte = 4; + else if (kilobyte > 16*1024) + kilobyte = 16*1024; + + iobuf_buffer_size = kilobyte * 1024; + used = 1; + } + return iobuf_buffer_size / 1024; +} + + #define MAX_IOBUF_DESC 32 /* * Fill the buffer by the description of iobuf A. @@ -1105,7 +1151,7 @@ iobuf_alloc (int use, size_t bufsize) if (bufsize == 0) { log_bug ("iobuf_alloc() passed a bufsize of 0!\n"); - bufsize = IOBUF_BUFFER_SIZE; + bufsize = iobuf_buffer_size; } a = xcalloc (1, sizeof *a); @@ -1213,7 +1259,7 @@ iobuf_cancel (iobuf_t a) iobuf_t iobuf_temp (void) { - return iobuf_alloc (IOBUF_OUTPUT_TEMP, IOBUF_BUFFER_SIZE); + return iobuf_alloc (IOBUF_OUTPUT_TEMP, iobuf_buffer_size); } iobuf_t @@ -1288,7 +1334,7 @@ do_open (const char *fname, int special_filenames, return NULL; } - a = iobuf_alloc (use, IOBUF_BUFFER_SIZE); + a = iobuf_alloc (use, iobuf_buffer_size); fcx = xmalloc (sizeof *fcx + strlen (fname)); fcx->fp = fp; fcx->print_only_name = print_only; @@ -1335,7 +1381,7 @@ do_iobuf_fdopen (int fd, const char *mode, int keep_open) fp = INT2FD (fd); a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT, - IOBUF_BUFFER_SIZE); + iobuf_buffer_size); fcx = xmalloc (sizeof *fcx + 20); fcx->fp = fp; fcx->print_only_name = 1; @@ -1373,7 +1419,7 @@ iobuf_esopen (estream_t estream, const char *mode, int keep_open) size_t len = 0; a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT, - IOBUF_BUFFER_SIZE); + iobuf_buffer_size); fcx = xtrymalloc (sizeof *fcx + 30); fcx->fp = estream; fcx->print_only_name = 1; @@ -1398,7 +1444,7 @@ iobuf_sockopen (int fd, const char *mode) size_t len; a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT, - IOBUF_BUFFER_SIZE); + iobuf_buffer_size); scx = xmalloc (sizeof *scx + 25); scx->sock = fd; scx->print_only_name = 1; @@ -1599,13 +1645,13 @@ iobuf_push_filter2 (iobuf_t a, increased accordingly. We don't need to allocate a 10 MB buffer for a non-terminal filter. Just use the default size. */ - a->d.size = IOBUF_BUFFER_SIZE; + a->d.size = iobuf_buffer_size; } else if (a->use == IOBUF_INPUT_TEMP) /* Same idea as above. */ { a->use = IOBUF_INPUT; - a->d.size = IOBUF_BUFFER_SIZE; + a->d.size = iobuf_buffer_size; } /* The new filter (A) gets a new buffer. @@ -1922,7 +1968,7 @@ filter_flush (iobuf_t a) if (a->use == IOBUF_OUTPUT_TEMP) { /* increase the temp buffer */ - size_t newsize = a->d.size + IOBUF_BUFFER_SIZE; + size_t newsize = a->d.size + iobuf_buffer_size; if (DBG_IOBUF) log_debug ("increasing temp iobuf from %lu to %lu\n", diff --git a/common/iobuf.h b/common/iobuf.h index 22e02daad..16156383c 100644 --- a/common/iobuf.h +++ b/common/iobuf.h @@ -259,6 +259,12 @@ struct iobuf_struct EXTERN_UNLESS_MAIN_MODULE int iobuf_debug_mode; +/* Change the default size for all IOBUFs to KILOBYTE. This needs to + * be called before any iobufs are used and can only be used once. + * Returns the current value. Using 0 has no effect except for + * returning the current value. */ +unsigned int iobuf_set_buffer_size (unsigned int kilobyte); + /* Returns whether the specified filename corresponds to a pipe. In particular, this function checks if FNAME is "-" and, if special filenames are enabled (see check_special_filename), whether diff --git a/common/logging.c b/common/logging.c index c4eaca411..88860e715 100644 --- a/common/logging.c +++ b/common/logging.c @@ -63,6 +63,10 @@ #include "logging.h" #include "sysutils.h" +#if defined(GPGRT_ENABLE_LOG_MACROS) && defined(log_debug_string) + /* Nothing to do; the libgpgrt functions are used. */ +#else /* Use our own logging functions. */ + #ifdef HAVE_W32_SYSTEM # ifndef S_IRWXG # define S_IRGRP S_IRUSR @@ -885,7 +889,7 @@ log_logv (int level, const char *fmt, va_list arg_ptr) * Note that PREFIX is an additional string and independent of the * prefix set by log_set_prefix. */ void -log_logv_with_prefix (int level, const char *prefix, +log_logv_prefix (int level, const char *prefix, const char *fmt, va_list arg_ptr) { do_logv (level, 0, NULL, prefix, fmt, arg_ptr); @@ -977,7 +981,7 @@ log_debug (const char *fmt, ...) * printed with LFs expanded to include the prefix and a final --end-- * marker. */ void -log_debug_with_string (const char *string, const char *fmt, ...) +log_debug_string (const char *string, const char *fmt, ...) { va_list arg_ptr ; @@ -1011,7 +1015,7 @@ log_flush (void) dump, with TEXT just an empty string, print a trailing linefeed, otherwise print an entire debug line. */ void -log_printhex (const char *text, const void *buffer, size_t length) +log_printhex (const void *buffer, size_t length, const char *text) { if (text && *text) log_debug ("%s ", text); @@ -1039,14 +1043,16 @@ log_printsexp () {} is found in sexputils.c */ - +/* Print a microsecond timestamp followed by a FORMAT. */ void -log_clock (const char *string) +log_clock (const char *fmt, ...) { -#if 0 +#if ENABLE_LOG_CLOCK static unsigned long long initial; struct timespec tv; unsigned long long now; + char clockbuf[50]; + va_list arg_ptr; if (clock_gettime (CLOCK_REALTIME, &tv)) { @@ -1059,11 +1065,21 @@ log_clock (const char *string) if (!initial) initial = now; - log_debug ("[%6llu] %s", (now - initial)/1000, string); -#else - /* You need to link with -ltr to enable the above code. */ - log_debug ("[not enabled in the source] %s", string); -#endif + snprintf (clockbuf, sizeof clockbuf, "[%6llu] ", (now - initial)/1000); + va_start (arg_ptr, fmt); + do_logv (GPGRT_LOG_DEBUG, 0, NULL, clockbuf, fmt, arg_ptr); + va_end (arg_ptr); + +#else /*!ENABLE_LOG_CLOCK*/ + + /* You may need to link with -ltr to use the above code. */ + va_list arg_ptr; + + va_start (arg_ptr, fmt); + do_logv (GPGRT_LOG_DEBUG, 0, NULL, "[no clock] ", fmt, arg_ptr); + va_end (arg_ptr); + +#endif /*!ENABLE_LOG_CLOCK*/ } @@ -1101,3 +1117,5 @@ _log_assert (const char *expr, const char *file, int line) abort (); /* Never called; just to make the compiler happy. */ } #endif /*!GPGRT_HAVE_MACRO_FUNCTION*/ + +#endif /* Use our own logging functions. */ diff --git a/common/logging.h b/common/logging.h index 2225100cb..a20b8f895 100644 --- a/common/logging.h +++ b/common/logging.h @@ -38,6 +38,35 @@ #include "mischelp.h" #include "w32help.h" +#if defined(GPGRT_ENABLE_LOG_MACROS) && defined(log_debug_string) + /* We use the libgpg-error provided log functions. but we need one + * more function: */ +# ifdef GPGRT_HAVE_MACRO_FUNCTION +# define BUG() bug_at ( __FILE__, __LINE__, __FUNCTION__) +static inline void bug_at (const char *file, int line, const char *func) + GPGRT_ATTR_NORETURN; +static inline void +bug_at (const char *file, int line, const char *func) +{ + gpgrt_log (GPGRT_LOGLVL_BUG, "there is a bug at %s:%d:%s\n", + file, line, func); + abort (); +} +# else +# define BUG() bug_at ( __FILE__, __LINE__) +static inline void bug_at (const char *file, int line) + GPGRT_ATTR_NORETURN; +static inline void +bug_at (const char *file, int line) +{ + gpgrt_log (GPGRT_LOGLVL_BUG, "there is a bug at %s:%d\n", file, line); + abort (); +} +# endif /*!GPGRT_HAVE_MACRO_FUNCTION*/ + + +#else /* Use gnupg internal logging functions. */ + int log_get_errorcount (int clear); void log_inc_errorcount (void); void log_set_file( const char *name ); @@ -88,18 +117,27 @@ enum jnlib_log_levels { GPGRT_LOG_BUG, GPGRT_LOG_DEBUG }; +#define GPGRT_LOGLVL_BEGIN GPGRT_LOG_BEGIN +#define GPGRT_LOGLVL_CONT GPGRT_LOG_CONT +#define GPGRT_LOGLVL_INFO GPGRT_LOG_INFO +#define GPGRT_LOGLVL_WARN GPGRT_LOG_WARN +#define GPGRT_LOGLVL_ERROR GPGRT_LOG_ERROR +#define GPGRT_LOGLVL_FATAL GPGRT_LOG_FATAL +#define GPGRT_LOGLVL_BUG GPGRT_LOG_BUG +#define GPGRT_LOGLVL_DEBUG GPGRT_LOG_DEBUG + void log_log (int level, const char *fmt, ...) GPGRT_ATTR_PRINTF(2,3); void log_logv (int level, const char *fmt, va_list arg_ptr); -void log_logv_with_prefix (int level, const char *prefix, - const char *fmt, va_list arg_ptr); +void log_logv_prefix (int level, const char *prefix, + const char *fmt, va_list arg_ptr); void log_string (int level, const char *string); void log_bug (const char *fmt, ...) GPGRT_ATTR_NR_PRINTF(1,2); void log_fatal (const char *fmt, ...) GPGRT_ATTR_NR_PRINTF(1,2); void log_error (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); void log_info (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); void log_debug (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); -void log_debug_with_string (const char *string, const char *fmt, - ...) GPGRT_ATTR_PRINTF(2,3); +void log_debug_string (const char *string, const char *fmt, + ...) GPGRT_ATTR_PRINTF(2,3); void log_printf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); void log_flush (void); @@ -107,10 +145,11 @@ void log_flush (void); raw dump, with TEXT being an empty string, print a trailing linefeed, otherwise print an entire debug line with TEXT followed by the hexdump and a final LF. */ -void log_printhex (const char *text, const void *buffer, size_t length); +void log_printhex (const void *buffer, size_t length, const char *text); -void log_clock (const char *string); +void log_clock (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); +#endif /* Use gnupg internal logging functions. */ /* Some handy assertion macros which don't abort. */ diff --git a/common/miscellaneous.c b/common/miscellaneous.c index 62ac05a84..0b374e6c8 100644 --- a/common/miscellaneous.c +++ b/common/miscellaneous.c @@ -45,14 +45,14 @@ my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr) /* Map the log levels. */ switch (level) { - case GCRY_LOG_CONT: level = GPGRT_LOG_CONT; break; - case GCRY_LOG_INFO: level = GPGRT_LOG_INFO; break; - case GCRY_LOG_WARN: level = GPGRT_LOG_WARN; break; - case GCRY_LOG_ERROR:level = GPGRT_LOG_ERROR; break; - case GCRY_LOG_FATAL:level = GPGRT_LOG_FATAL; break; - case GCRY_LOG_BUG: level = GPGRT_LOG_BUG; break; - case GCRY_LOG_DEBUG:level = GPGRT_LOG_DEBUG; break; - default: level = GPGRT_LOG_ERROR; break; + case GCRY_LOG_CONT: level = GPGRT_LOGLVL_CONT; break; + case GCRY_LOG_INFO: level = GPGRT_LOGLVL_INFO; break; + case GCRY_LOG_WARN: level = GPGRT_LOGLVL_WARN; break; + case GCRY_LOG_ERROR:level = GPGRT_LOGLVL_ERROR; break; + case GCRY_LOG_FATAL:level = GPGRT_LOGLVL_FATAL; break; + case GCRY_LOG_BUG: level = GPGRT_LOGLVL_BUG; break; + case GCRY_LOG_DEBUG:level = GPGRT_LOGLVL_DEBUG; break; + default: level = GPGRT_LOGLVL_ERROR; break; } log_logv (level, fmt, arg_ptr); } diff --git a/common/openpgpdefs.h b/common/openpgpdefs.h index 85a4251de..8699a178d 100644 --- a/common/openpgpdefs.h +++ b/common/openpgpdefs.h @@ -51,6 +51,7 @@ typedef enum PKT_ATTRIBUTE = 17, /* PGP's attribute packet. */ PKT_ENCRYPTED_MDC = 18, /* Integrity protected encrypted data. */ PKT_MDC = 19, /* Manipulation detection code packet. */ + PKT_ENCRYPTED_AEAD= 20, /* AEAD encrypted data packet. */ PKT_COMMENT = 61, /* new comment packet (GnuPG specific). */ PKT_GPG_CONTROL = 63 /* internal control packet (GnuPG specific). */ } @@ -115,7 +116,8 @@ typedef enum SIGSUBPKT_FEATURES = 30, /* Feature flags. */ SIGSUBPKT_SIGNATURE = 32, /* Embedded signature. */ - SIGSUBPKT_ISSUER_FPR = 33, /* EXPERIMENTAL: Issuer fingerprint. */ + SIGSUBPKT_ISSUER_FPR = 33, /* Issuer fingerprint. */ + SIGSUBPKT_PREF_AEAD = 34, /* Preferred AEAD algorithms. */ SIGSUBPKT_FLAG_CRITICAL = 128 } @@ -142,6 +144,16 @@ typedef enum cipher_algo_t; +/* Note that we encode the AEAD algo in a 3 bit field at some places. */ +typedef enum + { + AEAD_ALGO_NONE = 0, + AEAD_ALGO_EAX = 1, + AEAD_ALGO_OCB = 2 + } +aead_algo_t; + + typedef enum { PUBKEY_ALGO_RSA = 1, diff --git a/common/pkscreening.c b/common/pkscreening.c new file mode 100644 index 000000000..a3bfb474e --- /dev/null +++ b/common/pkscreening.c @@ -0,0 +1,159 @@ +/* pkscreening.c - Screen public keys for vulnerabilities + * Copyright (C) 2017 Werner Koch + * + * This file is part of GnuPG. + * + * This file 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. + * + * This file 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 Lesser General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdlib.h> + +#include "util.h" +#include "pkscreening.h" + + +/* Helper */ +static inline gpg_error_t +my_error (gpg_err_code_t ec) +{ + return gpg_err_make (default_errsource, ec); +} + + +/* Emulation of the new gcry_mpi_get_ui function. */ +static gpg_error_t +my_mpi_get_ui (unsigned int *v, gcry_mpi_t a) +{ + gpg_error_t err; + unsigned char buf[8]; + size_t n; + int i, mul; + + if (gcry_mpi_cmp_ui (a, 16384) > 0) + return my_error (GPG_ERR_ERANGE); /* Clearly too large for our purpose. */ + + err = gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, a); + if (err) + return err; + + *v = 0; + for (i = n - 1, mul = 1; i >= 0; i--, mul *= 256) + *v += mul * buf[i]; + + return 0; +} + + +/* Detect whether the MODULUS of a public RSA key is affected by the + * ROCA vulnerability as found in the Infinion RSA library + * (CVE-2017-15361). Returns 0 if not affected, GPG_ERR_TRUE if + * affected, GPG_ERR_BAD_MPI if an opaque RSA was passed, or other + * error codes if something weird happened */ +gpg_error_t +screen_key_for_roca (gcry_mpi_t modulus) +{ + static struct { + unsigned int prime_ui; + const char *print_hex; + gcry_mpi_t prime; + gcry_mpi_t print; + } table[] = { + { 3, "0x6" }, + { 5, "0x1E" }, + { 7, "0x7E" }, + { 11, "0x402" }, + { 13, "0x161A" }, + { 17, "0x1A316" }, + { 19, "0x30AF2" }, + { 23, "0x7FFFFE" }, + { 29, "0x1FFFFFFE" }, + { 31, "0x7FFFFFFE" }, + { 37, "0x4000402" }, + { 41, "0x1FFFFFFFFFE" }, + { 43, "0x7FFFFFFFFFE" }, + { 47, "0x7FFFFFFFFFFE" }, + { 53, "0x12DD703303AED2" }, + { 59, "0x7FFFFFFFFFFFFFE" }, + { 61, "0x1434026619900B0A" }, + { 67, "0x7FFFFFFFFFFFFFFFE" }, + { 71, "0x1164729716B1D977E" }, + { 73, "0x147811A48004962078A" }, + { 79, "0xB4010404000640502" }, + { 83, "0x7FFFFFFFFFFFFFFFFFFFE" }, + { 89, "0x1FFFFFFFFFFFFFFFFFFFFFE" }, + { 97, "0x1000000006000001800000002" }, + { 101, "0x1FFFFFFFFFFFFFFFFFFFFFFFFE" }, + { 103, "0x16380E9115BD964257768FE396" }, + { 107, "0x27816EA9821633397BE6A897E1A" }, + { 109, "0x1752639F4E85B003685CBE7192BA" }, + { 113, "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFE" }, + { 127, "0x6CA09850C2813205A04C81430A190536" }, + { 131, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" }, + { 137, "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" }, + { 139, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" }, + { 149, "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" }, + { 151, "0x50C018BC00482458DAC35B1A2412003D18030A" }, + { 157, "0x161FB414D76AF63826461899071BD5BACA0B7E1A" }, + { 163, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" }, + { 167, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" } + }; + gpg_error_t err; + int i; + gcry_mpi_t rem; + unsigned int bitno; + + /* Initialize on the first call. */ + if (!table[0].prime) + { + /* We pass primes[i] to the call so that in case of a concurrent + * second thread the already allocated space is reused. */ + for (i = 0; i < DIM (table); i++) + { + table[i].prime = gcry_mpi_set_ui (table[i].prime, table[i].prime_ui); + if (gcry_mpi_scan (&table[i].print, GCRYMPI_FMT_HEX, + table[i].print_hex, 0, NULL)) + BUG (); + } + } + + /* Check that it is not NULL or an opaque MPI. */ + if (!modulus || gcry_mpi_get_flag (modulus, GCRYMPI_FLAG_OPAQUE)) + return my_error (GPG_ERR_BAD_MPI); + + /* We divide the modulus of an RSA public key by a set of small + * PRIMEs and examine all the remainders. If all the bits at the + * index given by the remainder are set in the corresponding PRINT + * masks the key is very likely vulnerable. If any of the tested + * bits is zero, the key is not vulnerable. */ + rem = gcry_mpi_new (0); + for (i = 0; i < DIM (table); i++) + { + gcry_mpi_mod (rem, modulus, table[i].prime); + err = my_mpi_get_ui (&bitno, rem); + if (gpg_err_code (err) == GPG_ERR_ERANGE) + continue; + if (err) + goto leave; + if (!gcry_mpi_test_bit (table[i].print, bitno)) + goto leave; /* Not vulnerable. */ + } + + /* Very likely vulnerable */ + err = my_error (GPG_ERR_TRUE); + + leave: + gcry_mpi_release (rem); + return err; +} diff --git a/common/pkscreening.h b/common/pkscreening.h new file mode 100644 index 000000000..a64758924 --- /dev/null +++ b/common/pkscreening.h @@ -0,0 +1,26 @@ +/* pkscreening.c - Screen public keys for vulnerabilities + * Copyright (C) 2017 Werner Koch + * + * This file is part of GnuPG. + * + * This file 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. + * + * This file 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 Lesser General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef GNUPG_COMMON_PKSCREENING_H +#define GNUPG_COMMON_PKSCREENING_H + +gpg_error_t screen_key_for_roca (gcry_mpi_t modulus); + + +#endif /*GNUPG_COMMON_PKSCREENING_H*/ diff --git a/common/sysutils.c b/common/sysutils.c index e90010c44..55a7ee9ec 100644 --- a/common/sysutils.c +++ b/common/sysutils.c @@ -340,11 +340,10 @@ gnupg_usleep (unsigned int usecs) struct timespec req; struct timespec rem; - req.tv_sec = 0; - req.tv_nsec = usecs * 1000; - + req.tv_sec = usecs / 1000000; + req.tv_nsec = (usecs % 1000000) * 1000; while (nanosleep (&req, &rem) < 0 && errno == EINTR) - req = rem; + req = rem; } #else /*Standard Unix*/ diff --git a/common/util.h b/common/util.h index c6d19c64b..f3722812d 100644 --- a/common/util.h +++ b/common/util.h @@ -59,6 +59,11 @@ /* Hash function used with libksba. */ #define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write) +/* The length of the keygrip. This is a SHA-1 hash of the key + * parameters as generated by gcry_pk_get_keygrip. */ +#define KEYGRIP_LEN 20 + + /* Get all the stuff from jnlib. */ #include "../common/logging.h" #include "../common/argparse.h" |