diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/Makefile.am | 3 | ||||
-rw-r--r-- | common/exechelp-posix.c | 50 | ||||
-rw-r--r-- | common/gettime.c | 9 | ||||
-rw-r--r-- | common/logging.c | 12 | ||||
-rw-r--r-- | common/pkscreening.c | 159 | ||||
-rw-r--r-- | common/pkscreening.h | 26 | ||||
-rw-r--r-- | common/util.h | 5 |
7 files changed, 230 insertions, 34 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/exechelp-posix.c b/common/exechelp-posix.c index 7237993a2..3acf74ad6 100644 --- a/common/exechelp-posix.c +++ b/common/exechelp-posix.c @@ -784,30 +784,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/gettime.c b/common/gettime.c index 3e1ee5569..4ad99f54d 100644 --- a/common/gettime.c +++ b/common/gettime.c @@ -222,6 +222,8 @@ isotime_p (const char *string) for (s++, i=9; i < 15; i++, s++) if (!digitp (s)) return 0; + if (*s == 'Z') + s++; if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ',')) return 0; /* Wrong delimiter. */ @@ -354,9 +356,10 @@ string2isotime (gnupg_isotime_t atime, const char *string) } -/* Scan an ISO timestamp and return an Epoch based timestamp. The only - supported format is "yyyymmddThhmmss" delimited by white space, nul, a - colon or a comma. Returns (time_t)(-1) for an invalid string. */ +/* Scan an ISO timestamp and return an Epoch based timestamp. The + only supported format is "yyyymmddThhmmss[Z]" delimited by white + space, nul, a colon or a comma. Returns (time_t)(-1) for an + invalid string. */ time_t isotime2epoch (const char *string) { diff --git a/common/logging.c b/common/logging.c index c4eaca411..82b21e25b 100644 --- a/common/logging.c +++ b/common/logging.c @@ -1039,11 +1039,11 @@ log_printsexp () {} is found in sexputils.c */ - +/* Print a microsecond timestamp followed by STRING. */ void log_clock (const char *string) { -#if 0 +#if ENABLE_LOG_CLOCK static unsigned long long initial; struct timespec tv; unsigned long long now; @@ -1060,10 +1060,10 @@ log_clock (const char *string) 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 +#else /*!ENABLE_LOG_CLOCK*/ + /* You may need to link with -ltr to use the above code. */ + log_debug ("[not enabled by configure] %s", string); +#endif /*!ENABLE_LOG_CLOCK*/ } 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/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" |