]> git.ipfire.org Git - thirdparty/rng-tools.git/blame - rngd_rdrand.c
rngd_rdrand: Support compiling for x32 by adding unative_t
[thirdparty/rng-tools.git] / rngd_rdrand.c
CommitLineData
101309bc 1/*
62dec321 2 * Copyright (c) 2012-2014, Intel Corporation
101309bc 3 * Authors: Richard B. Hill <richard.b.hill@intel.com>,
04361df2
JM
4 * H. Peter Anvin <hpa@linux.intel.com>,
5 * John P. Mechalas <john.p.mechalas@intel.com>
101309bc
PA
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 */
21
22#define _GNU_SOURCE
23
24#ifndef HAVE_CONFIG_H
25#error Invalid or missing autoconf build environment
26#endif
27
28#include "rng-tools-config.h"
29
30#include <unistd.h>
31#include <stdint.h>
32#include <stdlib.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <fcntl.h>
36#include <errno.h>
37#include <syslog.h>
38#include <string.h>
39#include <stddef.h>
04361df2
JM
40#ifdef HAVE_LIBGCRYPT
41#include <gcrypt.h>
42#endif
101309bc
PA
43
44#include "rngd.h"
45#include "fips.h"
46#include "exits.h"
47#include "rngd_entsource.h"
48
49#if defined(__i386__) || defined(__x86_64__)
50
101309bc
PA
51/* Struct for CPUID return values */
52struct cpuid {
53 uint32_t eax, ecx, edx, ebx;
54};
55
56/* Get data from RDRAND */
57extern int x86_rdrand_nlong(void *ptr, size_t count);
58/* Conditioning RDRAND for seed-grade entropy */
59extern void x86_aes_mangle(void *data, void *state);
94f03c9a
PA
60/* Expand an AES key for future use */
61extern void x86_aes_expand_key(const void *key);
101309bc 62
0ad21ad0
PA
63#ifdef __x86_64__
64typedef uint64_t unative_t; /* x86-64 or x32 */
65#else
66typedef uint32_t unative_t; /* i386 */
67#endif
68
101309bc 69/* Checking eflags to confirm cpuid instruction available */
0ad21ad0 70static inline int x86_has_eflag(unative_t flag)
101309bc 71{
0ad21ad0 72 unative_t f0, f1;
62dec321
PA
73 asm("pushf ; "
74 "pushf ; "
75 "pop %0 ; "
76 "mov %0,%1 ; "
77 "xor %2,%1 ; "
78 "push %1 ; "
79 "popf ; "
80 "pushf ; "
81 "pop %1 ; "
82 "popf"
83 : "=&r" (f0), "=&r" (f1)
84 : "ri" (flag));
85 return !!((f0^f1) & flag);
101309bc 86}
62dec321
PA
87
88static inline int x86_has_cpuid(void)
89{
90#ifdef __i386__
91 return x86_has_eflag(1 << 21); /* ID flag */
92#else
93 return 1; /* x86-64 always has CPUID */
101309bc 94#endif
62dec321 95}
101309bc 96
04361df2 97/* Calling cpuid instruction to verify rdrand and aes-ni capability */
101309bc
PA
98static void cpuid(unsigned int leaf, unsigned int subleaf, struct cpuid *out)
99{
100#ifdef __i386__
101 /* %ebx is a forbidden register if we compile with -fPIC or -fPIE */
102 asm volatile("movl %%ebx,%0 ; cpuid ; xchgl %%ebx,%0"
103 : "=r" (out->ebx),
104 "=a" (out->eax),
105 "=c" (out->ecx),
106 "=d" (out->edx)
107 : "a" (leaf), "c" (subleaf));
108#else
109 asm volatile("cpuid"
110 : "=b" (out->ebx),
111 "=a" (out->eax),
112 "=c" (out->ecx),
113 "=d" (out->edx)
114 : "a" (leaf), "c" (subleaf));
115#endif
116}
117
932e25b2
PA
118/* Read data from the drng in chunks of 128 bytes for AES scrambling */
119#define CHUNK_SIZE (16*8)
120
121static unsigned char iv_buf[CHUNK_SIZE] __attribute__((aligned(128)));
62dec321 122static int have_aesni;
04361df2
JM
123
124/* Necessary if we have RDRAND but not AES-NI */
125
126#ifdef HAVE_LIBGCRYPT
127
128#define MIN_GCRYPT_VERSION "1.0.0"
129
130static gcry_cipher_hd_t gcry_cipher_hd;
131
62dec321 132#endif
04361df2 133
62dec321
PA
134static inline int gcrypt_mangle(unsigned char *tmp)
135{
136#ifdef HAVE_LIBGCRYPT
137 gcry_error_t gcry_error;
04361df2 138
62dec321 139 /* Encrypt tmp in-place. */
04361df2 140
62dec321
PA
141 gcry_error = gcry_cipher_encrypt(gcry_cipher_hd, tmp, CHUNK_SIZE,
142 NULL, 0);
143
144 if (gcry_error) {
145 message(LOG_DAEMON|LOG_ERR,
146 "gcry_cipher_encrypt error: %s\n",
147 gcry_strerror(gcry_error));
148 return -1;
149 }
150 return 0;
151#else
94f03c9a 152 (void)tmp;
62dec321
PA
153 return -1;
154#endif
155}
932e25b2 156
101309bc
PA
157int xread_drng(void *buf, size_t size, struct rng *ent_src)
158{
932e25b2
PA
159 char *p = buf;
160 size_t chunk;
161 const int rdrand_round_count = 512;
162 unsigned char tmp[CHUNK_SIZE] __attribute__((aligned(128)));
101309bc
PA
163 int i;
164
94f03c9a
PA
165 (void)ent_src;
166
932e25b2
PA
167 while (size) {
168 for (i = 0; i < rdrand_round_count; i++) {
0ad21ad0 169 if (!x86_rdrand_nlong(tmp, CHUNK_SIZE/sizeof(unative_t))) {
932e25b2
PA
170 message(LOG_DAEMON|LOG_ERR, "read error\n");
171 return -1;
101309bc 172 }
04361df2 173
62dec321
PA
174 /*
175 * Use 128-bit AES in CBC mode to reduce the
176 * data by a factor of rdrand_round_count
177 */
178 if (have_aesni)
179 x86_aes_mangle(tmp, iv_buf);
180 else if (gcrypt_mangle(tmp))
04361df2 181 return -1;
101309bc 182 }
932e25b2
PA
183 chunk = (sizeof(tmp) > size) ? size : sizeof(tmp);
184 memcpy(p, tmp, chunk);
185 p += chunk;
186 size -= chunk;
101309bc
PA
187 }
188
101309bc
PA
189 return 0;
190}
191
94f03c9a
PA
192static int init_aesni(const void *key)
193{
194 if (!have_aesni)
195 return 1;
196
197 x86_aes_expand_key(key);
198 return 0;
199}
200
201static int init_gcrypt(const void *key)
62dec321
PA
202{
203#ifdef HAVE_LIBGCRYPT
62dec321
PA
204 gcry_error_t gcry_error;
205
206 if (!gcry_check_version(MIN_GCRYPT_VERSION)) {
207 message(LOG_DAEMON|LOG_ERR,
208 "libgcrypt version mismatch: have %s, require >= %s\n",
209 gcry_check_version(NULL), MIN_GCRYPT_VERSION);
210 return 1;
211 }
212
213 gcry_error = gcry_cipher_open(&gcry_cipher_hd, GCRY_CIPHER_AES128,
214 GCRY_CIPHER_MODE_CBC, 0);
215
216 if (!gcry_error)
217 gcry_error = gcry_cipher_setkey(gcry_cipher_hd, key, 16);
218
219 if (!gcry_error) {
220 /*
221 * Only need the first 16 bytes of iv_buf. AES-NI can
222 * encrypt multiple blocks in parallel but we can't.
223 */
224 gcry_error = gcry_cipher_setiv(gcry_cipher_hd, iv_buf, 16);
225 }
226
227 if (gcry_error) {
228 message(LOG_DAEMON|LOG_ERR,
229 "could not set key or IV: %s\n",
230 gcry_strerror(gcry_error));
231 gcry_cipher_close(gcry_cipher_hd);
232 return 1;
233 }
234 return 0;
235#else
94f03c9a 236 (void)key;
62dec321
PA
237 return 1;
238#endif
239}
240
101309bc
PA
241/*
242 * Confirm RDRAND capabilities for drng entropy source
243 */
244int init_drng_entropy_source(struct rng *ent_src)
245{
246 struct cpuid info;
04361df2
JM
247 /* We need RDRAND, but AESni is optional */
248 const uint32_t features_ecx1_rdrand = 1 << 30;
62dec321 249 const uint32_t features_ecx1_aesni = 1 << 25;
94f03c9a
PA
250 static unsigned char key[16] = {
251 0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,
252 0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0
253 }; /* AES data reduction key */
254 unsigned char xkey[16]; /* Material to XOR into the key */
255 int fd;
256 int i;
101309bc 257
62dec321 258 if (!x86_has_cpuid())
101309bc 259 return 1; /* No CPUID instruction */
101309bc
PA
260
261 cpuid(0, 0, &info);
262 if (info.eax < 1)
263 return 1;
264 cpuid(1, 0, &info);
62dec321 265 if (!(info.ecx & features_ecx1_rdrand))
101309bc
PA
266 return 1;
267
62dec321
PA
268 have_aesni = !!(info.ecx & features_ecx1_aesni);
269
94f03c9a 270 /* Randomize the AES data reduction key the best we can */
0ad21ad0 271 if (!x86_rdrand_nlong(xkey, sizeof xkey/sizeof(unative_t)))
94f03c9a
PA
272 return 1;
273
274 fd = open("/dev/urandom", O_RDONLY);
275 if (fd >= 0) {
276 read(fd, key, sizeof key);
277 close(fd);
278 }
279
280 for (i = 0; i < sizeof key; i++)
281 key[i] ^= xkey[i];
04361df2 282
932e25b2 283 /* Initialize the IV buffer */
0ad21ad0 284 if (!x86_rdrand_nlong(iv_buf, CHUNK_SIZE/sizeof(unative_t)))
932e25b2
PA
285 return 1;
286
94f03c9a 287 if (init_aesni(key) && init_gcrypt(key))
62dec321 288 return 1; /* We need one crypto or the other... */
04361df2 289
101309bc
PA
290 src_list_add(ent_src);
291 /* Bootstrap FIPS tests */
292 ent_src->fipsctx = malloc(sizeof(fips_ctx_t));
293 fips_init(ent_src->fipsctx, 0);
294 return 0;
295}
296
297#else /* Not i386 or x86-64 */
298
299int init_drng_entropy_source(struct rng *ent_src)
300{
301 (void)ent_src;
302 return 1;
303}
304
305int xread_drng(void *buf, size_t size, struct rng *ent_src)
306{
307 (void)buf;
308 (void)size;
309 (void)ent_src;
310
311 return -1;
312}
313
314#endif /* Not i386 or x86-64 */