1 /* pkscreening.c - Screen public keys for vulnerabilities
2 * Copyright (C) 2017 Werner Koch
4 * This file is part of GnuPG.
6 * This file is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
11 * This file is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, see <https://www.gnu.org/licenses/>.
24 #include "pkscreening.h"
28 static inline gpg_error_t
29 my_error (gpg_err_code_t ec)
31 return gpg_err_make (default_errsource, ec);
35 /* Emulation of the new gcry_mpi_get_ui function. */
37 my_mpi_get_ui (unsigned int *v, gcry_mpi_t a)
44 if (gcry_mpi_cmp_ui (a, 16384) > 0)
45 return my_error (GPG_ERR_ERANGE); /* Clearly too large for our purpose. */
47 err = gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, a);
52 for (i = n - 1, mul = 1; i >= 0; i--, mul *= 256)
59 /* Detect whether the MODULUS of a public RSA key is affected by the
60 * ROCA vulnerability as found in the Infinion RSA library
61 * (CVE-2017-15361). Returns 0 if not affected, GPG_ERR_TRUE if
62 * affected, GPG_ERR_BAD_MPI if an opaque RSA was passed, or other
63 * error codes if something weird happened */
65 screen_key_for_roca (gcry_mpi_t modulus)
68 unsigned int prime_ui;
69 const char *print_hex;
84 { 41, "0x1FFFFFFFFFE" },
85 { 43, "0x7FFFFFFFFFE" },
86 { 47, "0x7FFFFFFFFFFE" },
87 { 53, "0x12DD703303AED2" },
88 { 59, "0x7FFFFFFFFFFFFFE" },
89 { 61, "0x1434026619900B0A" },
90 { 67, "0x7FFFFFFFFFFFFFFFE" },
91 { 71, "0x1164729716B1D977E" },
92 { 73, "0x147811A48004962078A" },
93 { 79, "0xB4010404000640502" },
94 { 83, "0x7FFFFFFFFFFFFFFFFFFFE" },
95 { 89, "0x1FFFFFFFFFFFFFFFFFFFFFE" },
96 { 97, "0x1000000006000001800000002" },
97 { 101, "0x1FFFFFFFFFFFFFFFFFFFFFFFFE" },
98 { 103, "0x16380E9115BD964257768FE396" },
99 { 107, "0x27816EA9821633397BE6A897E1A" },
100 { 109, "0x1752639F4E85B003685CBE7192BA" },
101 { 113, "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFE" },
102 { 127, "0x6CA09850C2813205A04C81430A190536" },
103 { 131, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" },
104 { 137, "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" },
105 { 139, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" },
106 { 149, "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" },
107 { 151, "0x50C018BC00482458DAC35B1A2412003D18030A" },
108 { 157, "0x161FB414D76AF63826461899071BD5BACA0B7E1A" },
109 { 163, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" },
110 { 167, "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" }
117 /* Initialize on the first call. */
120 /* We pass primes[i] to the call so that in case of a concurrent
121 * second thread the already allocated space is reused. */
122 for (i = 0; i < DIM (table); i++)
124 table[i].prime = gcry_mpi_set_ui (table[i].prime, table[i].prime_ui);
125 if (gcry_mpi_scan (&table[i].print, GCRYMPI_FMT_HEX,
126 table[i].print_hex, 0, NULL))
131 /* Check that it is not NULL or an opaque MPI. */
132 if (!modulus || gcry_mpi_get_flag (modulus, GCRYMPI_FLAG_OPAQUE))
133 return my_error (GPG_ERR_BAD_MPI);
135 /* We divide the modulus of an RSA public key by a set of small
136 * PRIMEs and examine all the remainders. If all the bits at the
137 * index given by the remainder are set in the corresponding PRINT
138 * masks the key is very likely vulnerable. If any of the tested
139 * bits is zero, the key is not vulnerable. */
140 rem = gcry_mpi_new (0);
141 for (i = 0; i < DIM (table); i++)
143 gcry_mpi_mod (rem, modulus, table[i].prime);
144 err = my_mpi_get_ui (&bitno, rem);
145 if (gpg_err_code (err) == GPG_ERR_ERANGE)
149 if (!gcry_mpi_test_bit (table[i].print, bitno))
150 goto leave; /* Not vulnerable. */
153 /* Very likely vulnerable */
154 err = my_error (GPG_ERR_TRUE);
157 gcry_mpi_release (rem);