Add a constant for a forthcoming new RNG.
[libgcrypt.git] / src / hwfeatures.c
1 /* hwfeatures.c - Detect hardware features.
2  * Copyright (C) 2007, 2011  Free Software Foundation, Inc.
3  * Copyright (C) 2012  g10 Code GmbH
4  *
5  * This file is part of Libgcrypt.
6  *
7  * Libgcrypt is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * Libgcrypt is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <ctype.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <unistd.h>
28 #ifdef HAVE_SYSLOG
29 # include <syslog.h>
30 #endif /*HAVE_SYSLOG*/
31
32 #include "g10lib.h"
33 #include "hwf-common.h"
34
35 /* The name of a file used to globally disable selected features. */
36 #define HWF_DENY_FILE "/etc/gcrypt/hwf.deny"
37
38 /* A table to map hardware features to a string.  */
39 static struct
40 {
41   unsigned int flag;
42   const char *desc;
43 } hwflist[] =
44   {
45     { HWF_PADLOCK_RNG, "padlock-rng" },
46     { HWF_PADLOCK_AES, "padlock-aes" },
47     { HWF_PADLOCK_SHA, "padlock-sha" },
48     { HWF_PADLOCK_MMUL,"padlock-mmul"},
49     { HWF_INTEL_CPU,   "intel-cpu" },
50     { HWF_INTEL_BMI2,  "intel-bmi2" },
51     { HWF_INTEL_SSSE3, "intel-ssse3" },
52     { HWF_INTEL_PCLMUL,"intel-pclmul" },
53     { HWF_INTEL_AESNI, "intel-aesni" },
54     { HWF_INTEL_RDRAND,"intel-rdrand" },
55     { HWF_INTEL_AVX,   "intel-avx" },
56     { HWF_INTEL_AVX2,  "intel-avx2" },
57     { HWF_ARM_NEON,    "arm-neon" }
58   };
59
60 /* A bit vector with the hardware features which shall not be used.
61    This variable must be set prior to any initialization.  */
62 static unsigned int disabled_hw_features;
63
64 /* A bit vector describing the hardware features currently
65    available. */
66 static unsigned int hw_features;
67
68 /* Convenience macros.  */
69 #define my_isascii(c) (!((c) & 0x80))
70
71
72 \f
73 /* Disable a feature by name.  This function must be called *before*
74    _gcry_detect_hw_features is called.  */
75 gpg_err_code_t
76 _gcry_disable_hw_feature (const char *name)
77 {
78   int i;
79
80   for (i=0; i < DIM (hwflist); i++)
81     if (!strcmp (hwflist[i].desc, name))
82       {
83         disabled_hw_features |= hwflist[i].flag;
84         return 0;
85       }
86   return GPG_ERR_INV_NAME;
87 }
88
89
90 /* Return a bit vector describing the available hardware features.
91    The HWF_ constants are used to test for them. */
92 unsigned int
93 _gcry_get_hw_features (void)
94 {
95   return hw_features;
96 }
97
98
99 /* Enumerate all features.  The caller is expected to start with an
100    IDX of 0 and then increment IDX until NULL is returned.  */
101 const char *
102 _gcry_enum_hw_features (int idx, unsigned int *r_feature)
103 {
104   if (idx < 0 || idx >= DIM (hwflist))
105     return NULL;
106   if (r_feature)
107     *r_feature = hwflist[idx].flag;
108   return hwflist[idx].desc;
109 }
110
111
112 /* Read a file with features which shall not be used.  The file is a
113    simple text file where empty lines and lines with the first non
114    white-space character being '#' are ignored.  */
115 static void
116 parse_hwf_deny_file (void)
117 {
118   const char *fname = HWF_DENY_FILE;
119   FILE *fp;
120   char buffer[256];
121   char *p, *pend;
122   int i, lnr = 0;
123
124   fp = fopen (fname, "r");
125   if (!fp)
126     return;
127
128   for (;;)
129     {
130       if (!fgets (buffer, sizeof buffer, fp))
131         {
132           if (!feof (fp))
133             {
134 #ifdef HAVE_SYSLOG
135               syslog (LOG_USER|LOG_WARNING,
136                       "Libgcrypt warning: error reading '%s', line %d",
137                       fname, lnr);
138 #endif /*HAVE_SYSLOG*/
139             }
140           fclose (fp);
141           return;
142         }
143       lnr++;
144       for (p=buffer; my_isascii (*p) && isspace (*p); p++)
145         ;
146       pend = strchr (p, '\n');
147       if (pend)
148         *pend = 0;
149       pend = p + (*p? (strlen (p)-1):0);
150       for ( ;pend > p; pend--)
151         if (my_isascii (*pend) && isspace (*pend))
152           *pend = 0;
153       if (!*p || *p == '#')
154         continue;
155
156       for (i=0; i < DIM (hwflist); i++)
157         {
158           if (!strcmp (hwflist[i].desc, p))
159             {
160               disabled_hw_features |= hwflist[i].flag;
161               break;
162             }
163         }
164       if (i == DIM (hwflist))
165         {
166 #ifdef HAVE_SYSLOG
167           syslog (LOG_USER|LOG_WARNING,
168                   "Libgcrypt warning: unknown feature in '%s', line %d",
169                   fname, lnr);
170 #endif /*HAVE_SYSLOG*/
171         }
172     }
173 }
174
175
176 /* Detect the available hardware features.  This function is called
177    once right at startup and we assume that no other threads are
178    running.  */
179 void
180 _gcry_detect_hw_features (void)
181 {
182   hw_features = 0;
183
184   if (fips_mode ())
185     return; /* Hardware support is not to be evaluated.  */
186
187   parse_hwf_deny_file ();
188
189 #if defined (HAVE_CPU_ARCH_X86)
190   {
191     hw_features = _gcry_hwf_detect_x86 ();
192   }
193 #endif /* HAVE_CPU_ARCH_X86 */
194 #if defined (HAVE_CPU_ARCH_ARM)
195   {
196     hw_features = _gcry_hwf_detect_arm ();
197   }
198 #endif /* HAVE_CPU_ARCH_ARM */
199
200   hw_features &= ~disabled_hw_features;
201 }