]> git.ipfire.org Git - thirdparty/rng-tools.git/blob - rngd_rdrand.c
rngd_rdrand: Code style cleanups
[thirdparty/rng-tools.git] / rngd_rdrand.c
1 /*
2 * Copyright (c) 2012-2014, Intel Corporation
3 * Authors: Richard B. Hill <richard.b.hill@intel.com>,
4 * H. Peter Anvin <hpa@linux.intel.com>,
5 * John P. Mechalas <john.p.mechalas@intel.com>
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>
40 #ifdef HAVE_LIBGCRYPT
41 #include <gcrypt.h>
42 #endif
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
51 /* Struct for CPUID return values */
52 struct cpuid {
53 uint32_t eax, ecx, edx, ebx;
54 };
55
56 /* Get data from RDRAND */
57 extern int x86_rdrand_nlong(void *ptr, size_t count);
58 /* Conditioning RDRAND for seed-grade entropy */
59 extern void x86_aes_mangle(void *data, void *state);
60
61 /* Checking eflags to confirm cpuid instruction available */
62 static inline int x86_has_eflag(unsigned long flag)
63 {
64 unsigned long f0, f1;
65 asm("pushf ; "
66 "pushf ; "
67 "pop %0 ; "
68 "mov %0,%1 ; "
69 "xor %2,%1 ; "
70 "push %1 ; "
71 "popf ; "
72 "pushf ; "
73 "pop %1 ; "
74 "popf"
75 : "=&r" (f0), "=&r" (f1)
76 : "ri" (flag));
77 return !!((f0^f1) & flag);
78 }
79
80 static inline int x86_has_cpuid(void)
81 {
82 #ifdef __i386__
83 return x86_has_eflag(1 << 21); /* ID flag */
84 #else
85 return 1; /* x86-64 always has CPUID */
86 #endif
87 }
88
89 /* Calling cpuid instruction to verify rdrand and aes-ni capability */
90 static void cpuid(unsigned int leaf, unsigned int subleaf, struct cpuid *out)
91 {
92 #ifdef __i386__
93 /* %ebx is a forbidden register if we compile with -fPIC or -fPIE */
94 asm volatile("movl %%ebx,%0 ; cpuid ; xchgl %%ebx,%0"
95 : "=r" (out->ebx),
96 "=a" (out->eax),
97 "=c" (out->ecx),
98 "=d" (out->edx)
99 : "a" (leaf), "c" (subleaf));
100 #else
101 asm volatile("cpuid"
102 : "=b" (out->ebx),
103 "=a" (out->eax),
104 "=c" (out->ecx),
105 "=d" (out->edx)
106 : "a" (leaf), "c" (subleaf));
107 #endif
108 }
109
110 /* Read data from the drng in chunks of 128 bytes for AES scrambling */
111 #define CHUNK_SIZE (16*8)
112
113 static unsigned char iv_buf[CHUNK_SIZE] __attribute__((aligned(128)));
114 static int have_aesni;
115
116 /* Necessary if we have RDRAND but not AES-NI */
117
118 #ifdef HAVE_LIBGCRYPT
119
120 #define MIN_GCRYPT_VERSION "1.0.0"
121
122 static gcry_cipher_hd_t gcry_cipher_hd;
123
124 #endif
125
126 static inline int gcrypt_mangle(unsigned char *tmp)
127 {
128 #ifdef HAVE_LIBGCRYPT
129 gcry_error_t gcry_error;
130
131 /* Encrypt tmp in-place. */
132
133 gcry_error = gcry_cipher_encrypt(gcry_cipher_hd, tmp, CHUNK_SIZE,
134 NULL, 0);
135
136 if (gcry_error) {
137 message(LOG_DAEMON|LOG_ERR,
138 "gcry_cipher_encrypt error: %s\n",
139 gcry_strerror(gcry_error));
140 return -1;
141 }
142 return 0;
143 #else
144 return -1;
145 #endif
146 }
147
148 int xread_drng(void *buf, size_t size, struct rng *ent_src)
149 {
150 char *p = buf;
151 size_t chunk;
152 const int rdrand_round_count = 512;
153 unsigned char tmp[CHUNK_SIZE] __attribute__((aligned(128)));
154 int i;
155
156 while (size) {
157 for (i = 0; i < rdrand_round_count; i++) {
158 if (!x86_rdrand_nlong(tmp, CHUNK_SIZE/sizeof(long))) {
159 message(LOG_DAEMON|LOG_ERR, "read error\n");
160 return -1;
161 }
162
163 /*
164 * Use 128-bit AES in CBC mode to reduce the
165 * data by a factor of rdrand_round_count
166 */
167 if (have_aesni)
168 x86_aes_mangle(tmp, iv_buf);
169 else if (gcrypt_mangle(tmp))
170 return -1;
171 }
172 chunk = (sizeof(tmp) > size) ? size : sizeof(tmp);
173 memcpy(p, tmp, chunk);
174 p += chunk;
175 size -= chunk;
176 }
177
178 return 0;
179 }
180
181 static int init_gcrypt(void)
182 {
183 #ifdef HAVE_LIBGCRYPT
184 /* Arbitrary 128-bit AES key 0x00102030405060708090A0B0C0D0E0F0 */
185 static const unsigned char key[16] = {
186 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
187 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0
188 };
189 gcry_error_t gcry_error;
190
191 if (!gcry_check_version(MIN_GCRYPT_VERSION)) {
192 message(LOG_DAEMON|LOG_ERR,
193 "libgcrypt version mismatch: have %s, require >= %s\n",
194 gcry_check_version(NULL), MIN_GCRYPT_VERSION);
195 return 1;
196 }
197
198 gcry_error = gcry_cipher_open(&gcry_cipher_hd, GCRY_CIPHER_AES128,
199 GCRY_CIPHER_MODE_CBC, 0);
200
201 if (!gcry_error)
202 gcry_error = gcry_cipher_setkey(gcry_cipher_hd, key, 16);
203
204 if (!gcry_error) {
205 /*
206 * Only need the first 16 bytes of iv_buf. AES-NI can
207 * encrypt multiple blocks in parallel but we can't.
208 */
209 gcry_error = gcry_cipher_setiv(gcry_cipher_hd, iv_buf, 16);
210 }
211
212 if (gcry_error) {
213 message(LOG_DAEMON|LOG_ERR,
214 "could not set key or IV: %s\n",
215 gcry_strerror(gcry_error));
216 gcry_cipher_close(gcry_cipher_hd);
217 return 1;
218 }
219 return 0;
220 #else
221 return 1;
222 #endif
223 }
224
225 /*
226 * Confirm RDRAND capabilities for drng entropy source
227 */
228 int init_drng_entropy_source(struct rng *ent_src)
229 {
230 struct cpuid info;
231 /* We need RDRAND, but AESni is optional */
232 const uint32_t features_ecx1_rdrand = 1 << 30;
233 const uint32_t features_ecx1_aesni = 1 << 25;
234
235 if (!x86_has_cpuid())
236 return 1; /* No CPUID instruction */
237
238 cpuid(0, 0, &info);
239 if (info.eax < 1)
240 return 1;
241 cpuid(1, 0, &info);
242 if (!(info.ecx & features_ecx1_rdrand))
243 return 1;
244
245 have_aesni = !!(info.ecx & features_ecx1_aesni);
246
247 /* Initialize the AES key */
248
249 /* Initialize the IV buffer */
250 if (!x86_rdrand_nlong(iv_buf, CHUNK_SIZE/sizeof(long)))
251 return 1;
252
253 if (!have_aesni && init_gcrypt())
254 return 1; /* We need one crypto or the other... */
255
256 src_list_add(ent_src);
257 /* Bootstrap FIPS tests */
258 ent_src->fipsctx = malloc(sizeof(fips_ctx_t));
259 fips_init(ent_src->fipsctx, 0);
260 return 0;
261 }
262
263 #else /* Not i386 or x86-64 */
264
265 int init_drng_entropy_source(struct rng *ent_src)
266 {
267 (void)ent_src;
268 return 1;
269 }
270
271 int xread_drng(void *buf, size_t size, struct rng *ent_src)
272 {
273 (void)buf;
274 (void)size;
275 (void)ent_src;
276
277 return -1;
278 }
279
280 #endif /* Not i386 or x86-64 */