agent: Fix segv running in --server mode
[gnupg.git] / common / pkscreening.c
1 /* pkscreening.c - Screen public keys for vulnerabilities
2  * Copyright (C) 2017 Werner Koch
3  *
4  * This file is part of GnuPG.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include <config.h>
21 #include <stdlib.h>
22
23 #include "util.h"
24 #include "pkscreening.h"
25
26
27 /* Helper */
28 static inline gpg_error_t
29 my_error (gpg_err_code_t ec)
30 {
31   return gpg_err_make (default_errsource, ec);
32 }
33
34
35 /* Emulation of the new gcry_mpi_get_ui function.  */
36 static gpg_error_t
37 my_mpi_get_ui (unsigned int *v, gcry_mpi_t a)
38 {
39   gpg_error_t err;
40   unsigned char buf[8];
41   size_t n;
42   int i, mul;
43
44   if (gcry_mpi_cmp_ui (a, 16384) > 0)
45     return my_error (GPG_ERR_ERANGE); /* Clearly too large for our purpose.  */
46
47   err = gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, a);
48   if (err)
49     return err;
50
51   *v = 0;
52   for (i = n - 1, mul = 1; i >= 0; i--, mul *= 256)
53     *v += mul * buf[i];
54
55   return 0;
56 }
57
58
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  */
64 gpg_error_t
65 screen_key_for_roca (gcry_mpi_t modulus)
66 {
67   static struct {
68     unsigned int prime_ui;
69     const char *print_hex;
70     gcry_mpi_t prime;
71     gcry_mpi_t print;
72   } table[] = {
73    { 3,   "0x6" },
74    { 5,   "0x1E" },
75    { 7,   "0x7E" },
76    { 11,  "0x402" },
77    { 13,  "0x161A" },
78    { 17,  "0x1A316" },
79    { 19,  "0x30AF2" },
80    { 23,  "0x7FFFFE" },
81    { 29,  "0x1FFFFFFE" },
82    { 31,  "0x7FFFFFFE" },
83    { 37,  "0x4000402"  },
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" }
111   };
112   gpg_error_t err;
113   int i;
114   gcry_mpi_t rem;
115   unsigned int bitno;
116
117   /* Initialize on the first call. */
118   if (!table[0].prime)
119     {
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++)
123         {
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))
127             BUG ();
128         }
129     }
130
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);
134
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++)
142     {
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)
146         continue;
147       if (err)
148         goto leave;
149       if (!gcry_mpi_test_bit (table[i].print, bitno))
150         goto leave;  /* Not vulnerable.  */
151     }
152
153   /* Very likely vulnerable */
154   err = my_error (GPG_ERR_TRUE);
155
156  leave:
157   gcry_mpi_release (rem);
158   return err;
159 }