]>
Commit | Line | Data |
---|---|---|
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 */ |
52 | struct cpuid { | |
53 | uint32_t eax, ecx, edx, ebx; | |
54 | }; | |
55 | ||
3164d3eb PA |
56 | /* |
57 | * Get data from RDRAND. The count is in bytes, but the function can | |
58 | * round *up* the count to the nearest 4- or 8-byte boundary. The caller | |
59 | * needs to take that into account. | |
60 | * | |
61 | * The function returns the number of bytes actually written. | |
62 | */ | |
63 | extern unsigned int x86_rdrand_bytes(void *ptr, unsigned int count); | |
64 | ||
65 | /* Condition RDRAND for seed-grade entropy */ | |
101309bc | 66 | extern void x86_aes_mangle(void *data, void *state); |
3164d3eb | 67 | |
94f03c9a PA |
68 | /* Expand an AES key for future use */ |
69 | extern void x86_aes_expand_key(const void *key); | |
101309bc | 70 | |
0ad21ad0 PA |
71 | #ifdef __x86_64__ |
72 | typedef uint64_t unative_t; /* x86-64 or x32 */ | |
73 | #else | |
74 | typedef uint32_t unative_t; /* i386 */ | |
75 | #endif | |
76 | ||
101309bc | 77 | /* Checking eflags to confirm cpuid instruction available */ |
0ad21ad0 | 78 | static inline int x86_has_eflag(unative_t flag) |
101309bc | 79 | { |
0ad21ad0 | 80 | unative_t f0, f1; |
62dec321 PA |
81 | asm("pushf ; " |
82 | "pushf ; " | |
83 | "pop %0 ; " | |
84 | "mov %0,%1 ; " | |
85 | "xor %2,%1 ; " | |
86 | "push %1 ; " | |
87 | "popf ; " | |
88 | "pushf ; " | |
89 | "pop %1 ; " | |
90 | "popf" | |
91 | : "=&r" (f0), "=&r" (f1) | |
92 | : "ri" (flag)); | |
93 | return !!((f0^f1) & flag); | |
101309bc | 94 | } |
62dec321 PA |
95 | |
96 | static inline int x86_has_cpuid(void) | |
97 | { | |
98 | #ifdef __i386__ | |
99 | return x86_has_eflag(1 << 21); /* ID flag */ | |
100 | #else | |
101 | return 1; /* x86-64 always has CPUID */ | |
101309bc | 102 | #endif |
62dec321 | 103 | } |
101309bc | 104 | |
04361df2 | 105 | /* Calling cpuid instruction to verify rdrand and aes-ni capability */ |
101309bc PA |
106 | static void cpuid(unsigned int leaf, unsigned int subleaf, struct cpuid *out) |
107 | { | |
108 | #ifdef __i386__ | |
109 | /* %ebx is a forbidden register if we compile with -fPIC or -fPIE */ | |
110 | asm volatile("movl %%ebx,%0 ; cpuid ; xchgl %%ebx,%0" | |
111 | : "=r" (out->ebx), | |
112 | "=a" (out->eax), | |
113 | "=c" (out->ecx), | |
114 | "=d" (out->edx) | |
115 | : "a" (leaf), "c" (subleaf)); | |
116 | #else | |
117 | asm volatile("cpuid" | |
118 | : "=b" (out->ebx), | |
119 | "=a" (out->eax), | |
120 | "=c" (out->ecx), | |
121 | "=d" (out->edx) | |
122 | : "a" (leaf), "c" (subleaf)); | |
123 | #endif | |
124 | } | |
125 | ||
932e25b2 | 126 | /* Read data from the drng in chunks of 128 bytes for AES scrambling */ |
3e89e082 PA |
127 | #define AES_BLOCK 16 |
128 | #define CHUNK_SIZE (AES_BLOCK*8) /* 8 parallel streams */ | |
129 | #define RDRAND_ROUNDS 512 /* 512:1 data reduction */ | |
932e25b2 PA |
130 | |
131 | static unsigned char iv_buf[CHUNK_SIZE] __attribute__((aligned(128))); | |
62dec321 | 132 | static int have_aesni; |
04361df2 JM |
133 | |
134 | /* Necessary if we have RDRAND but not AES-NI */ | |
135 | ||
136 | #ifdef HAVE_LIBGCRYPT | |
137 | ||
138 | #define MIN_GCRYPT_VERSION "1.0.0" | |
139 | ||
140 | static gcry_cipher_hd_t gcry_cipher_hd; | |
141 | ||
62dec321 | 142 | #endif |
04361df2 | 143 | |
62dec321 PA |
144 | static inline int gcrypt_mangle(unsigned char *tmp) |
145 | { | |
146 | #ifdef HAVE_LIBGCRYPT | |
147 | gcry_error_t gcry_error; | |
04361df2 | 148 | |
62dec321 | 149 | /* Encrypt tmp in-place. */ |
04361df2 | 150 | |
3e89e082 PA |
151 | gcry_error = gcry_cipher_encrypt(gcry_cipher_hd, tmp, |
152 | AES_BLOCK * RDRAND_ROUNDS, | |
62dec321 PA |
153 | NULL, 0); |
154 | ||
155 | if (gcry_error) { | |
156 | message(LOG_DAEMON|LOG_ERR, | |
157 | "gcry_cipher_encrypt error: %s\n", | |
158 | gcry_strerror(gcry_error)); | |
159 | return -1; | |
160 | } | |
161 | return 0; | |
162 | #else | |
94f03c9a | 163 | (void)tmp; |
62dec321 PA |
164 | return -1; |
165 | #endif | |
166 | } | |
932e25b2 | 167 | |
101309bc PA |
168 | int xread_drng(void *buf, size_t size, struct rng *ent_src) |
169 | { | |
932e25b2 PA |
170 | char *p = buf; |
171 | size_t chunk; | |
3e89e082 PA |
172 | void *data; |
173 | unsigned char rdrand_buf[CHUNK_SIZE * RDRAND_ROUNDS] | |
174 | __attribute__((aligned(128))); | |
175 | unsigned int rand_bytes; | |
101309bc PA |
176 | int i; |
177 | ||
94f03c9a PA |
178 | (void)ent_src; |
179 | ||
3e89e082 PA |
180 | rand_bytes = have_aesni |
181 | ? CHUNK_SIZE * RDRAND_ROUNDS | |
182 | : AES_BLOCK * RDRAND_ROUNDS; | |
183 | ||
932e25b2 | 184 | while (size) { |
3e89e082 PA |
185 | if (x86_rdrand_bytes(rdrand_buf, rand_bytes) != rand_bytes) { |
186 | message(LOG_DAEMON|LOG_ERR, "read error\n"); | |
187 | return -1; | |
188 | } | |
189 | ||
190 | /* | |
191 | * Use 128-bit AES in CBC mode to reduce the | |
192 | * data by a factor of RDRAND_ROUNDS | |
193 | */ | |
194 | if (have_aesni) { | |
195 | x86_aes_mangle(rdrand_buf, iv_buf); | |
196 | data = iv_buf; | |
197 | chunk = CHUNK_SIZE; | |
198 | } else if (!gcrypt_mangle(rdrand_buf)) { | |
199 | data = rdrand_buf + AES_BLOCK * (RDRAND_ROUNDS - 1); | |
200 | chunk = AES_BLOCK; | |
201 | } else { | |
202 | return -1; | |
101309bc | 203 | } |
3e89e082 PA |
204 | |
205 | chunk = (chunk > size) ? size : chunk; | |
206 | memcpy(p, data, chunk); | |
932e25b2 PA |
207 | p += chunk; |
208 | size -= chunk; | |
101309bc PA |
209 | } |
210 | ||
101309bc PA |
211 | return 0; |
212 | } | |
213 | ||
94f03c9a PA |
214 | static int init_aesni(const void *key) |
215 | { | |
216 | if (!have_aesni) | |
217 | return 1; | |
218 | ||
219 | x86_aes_expand_key(key); | |
220 | return 0; | |
221 | } | |
222 | ||
223 | static int init_gcrypt(const void *key) | |
62dec321 PA |
224 | { |
225 | #ifdef HAVE_LIBGCRYPT | |
62dec321 PA |
226 | gcry_error_t gcry_error; |
227 | ||
228 | if (!gcry_check_version(MIN_GCRYPT_VERSION)) { | |
229 | message(LOG_DAEMON|LOG_ERR, | |
230 | "libgcrypt version mismatch: have %s, require >= %s\n", | |
231 | gcry_check_version(NULL), MIN_GCRYPT_VERSION); | |
232 | return 1; | |
233 | } | |
234 | ||
235 | gcry_error = gcry_cipher_open(&gcry_cipher_hd, GCRY_CIPHER_AES128, | |
236 | GCRY_CIPHER_MODE_CBC, 0); | |
237 | ||
238 | if (!gcry_error) | |
3e89e082 | 239 | gcry_error = gcry_cipher_setkey(gcry_cipher_hd, key, AES_BLOCK); |
62dec321 PA |
240 | |
241 | if (!gcry_error) { | |
242 | /* | |
243 | * Only need the first 16 bytes of iv_buf. AES-NI can | |
244 | * encrypt multiple blocks in parallel but we can't. | |
245 | */ | |
3e89e082 | 246 | gcry_error = gcry_cipher_setiv(gcry_cipher_hd, iv_buf, AES_BLOCK); |
62dec321 PA |
247 | } |
248 | ||
249 | if (gcry_error) { | |
250 | message(LOG_DAEMON|LOG_ERR, | |
251 | "could not set key or IV: %s\n", | |
252 | gcry_strerror(gcry_error)); | |
253 | gcry_cipher_close(gcry_cipher_hd); | |
254 | return 1; | |
255 | } | |
256 | return 0; | |
257 | #else | |
94f03c9a | 258 | (void)key; |
62dec321 PA |
259 | return 1; |
260 | #endif | |
261 | } | |
262 | ||
101309bc PA |
263 | /* |
264 | * Confirm RDRAND capabilities for drng entropy source | |
265 | */ | |
266 | int init_drng_entropy_source(struct rng *ent_src) | |
267 | { | |
268 | struct cpuid info; | |
04361df2 JM |
269 | /* We need RDRAND, but AESni is optional */ |
270 | const uint32_t features_ecx1_rdrand = 1 << 30; | |
62dec321 | 271 | const uint32_t features_ecx1_aesni = 1 << 25; |
3e89e082 | 272 | static unsigned char key[AES_BLOCK] = { |
94f03c9a PA |
273 | 0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70, |
274 | 0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0 | |
275 | }; /* AES data reduction key */ | |
3e89e082 | 276 | unsigned char xkey[AES_BLOCK]; /* Material to XOR into the key */ |
94f03c9a PA |
277 | int fd; |
278 | int i; | |
101309bc | 279 | |
62dec321 | 280 | if (!x86_has_cpuid()) |
101309bc | 281 | return 1; /* No CPUID instruction */ |
101309bc PA |
282 | |
283 | cpuid(0, 0, &info); | |
284 | if (info.eax < 1) | |
285 | return 1; | |
286 | cpuid(1, 0, &info); | |
62dec321 | 287 | if (!(info.ecx & features_ecx1_rdrand)) |
101309bc PA |
288 | return 1; |
289 | ||
62dec321 PA |
290 | have_aesni = !!(info.ecx & features_ecx1_aesni); |
291 | ||
94f03c9a | 292 | /* Randomize the AES data reduction key the best we can */ |
3164d3eb | 293 | if (x86_rdrand_bytes(xkey, sizeof xkey) != sizeof xkey) |
94f03c9a PA |
294 | return 1; |
295 | ||
296 | fd = open("/dev/urandom", O_RDONLY); | |
297 | if (fd >= 0) { | |
298 | read(fd, key, sizeof key); | |
299 | close(fd); | |
300 | } | |
301 | ||
302 | for (i = 0; i < sizeof key; i++) | |
303 | key[i] ^= xkey[i]; | |
04361df2 | 304 | |
932e25b2 | 305 | /* Initialize the IV buffer */ |
3164d3eb | 306 | if (x86_rdrand_bytes(iv_buf, CHUNK_SIZE) != CHUNK_SIZE) |
932e25b2 PA |
307 | return 1; |
308 | ||
94f03c9a | 309 | if (init_aesni(key) && init_gcrypt(key)) |
62dec321 | 310 | return 1; /* We need one crypto or the other... */ |
04361df2 | 311 | |
101309bc PA |
312 | src_list_add(ent_src); |
313 | /* Bootstrap FIPS tests */ | |
314 | ent_src->fipsctx = malloc(sizeof(fips_ctx_t)); | |
315 | fips_init(ent_src->fipsctx, 0); | |
316 | return 0; | |
317 | } | |
318 | ||
319 | #else /* Not i386 or x86-64 */ | |
320 | ||
321 | int init_drng_entropy_source(struct rng *ent_src) | |
322 | { | |
323 | (void)ent_src; | |
324 | return 1; | |
325 | } | |
326 | ||
327 | int xread_drng(void *buf, size_t size, struct rng *ent_src) | |
328 | { | |
329 | (void)buf; | |
330 | (void)size; | |
331 | (void)ent_src; | |
332 | ||
333 | return -1; | |
334 | } | |
335 | ||
336 | #endif /* Not i386 or x86-64 */ |