]>
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 | ||
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); | |
94f03c9a PA |
60 | /* Expand an AES key for future use */ |
61 | extern void x86_aes_expand_key(const void *key); | |
101309bc | 62 | |
0ad21ad0 PA |
63 | #ifdef __x86_64__ |
64 | typedef uint64_t unative_t; /* x86-64 or x32 */ | |
65 | #else | |
66 | typedef uint32_t unative_t; /* i386 */ | |
67 | #endif | |
68 | ||
101309bc | 69 | /* Checking eflags to confirm cpuid instruction available */ |
0ad21ad0 | 70 | static 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 | |
88 | static 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 |
98 | static 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 | ||
121 | static unsigned char iv_buf[CHUNK_SIZE] __attribute__((aligned(128))); | |
62dec321 | 122 | static 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 | ||
130 | static gcry_cipher_hd_t gcry_cipher_hd; | |
131 | ||
62dec321 | 132 | #endif |
04361df2 | 133 | |
62dec321 PA |
134 | static 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 |
157 | int 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 |
192 | static 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 | ||
201 | static 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 | */ | |
244 | int 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 | ||
299 | int init_drng_entropy_source(struct rng *ent_src) | |
300 | { | |
301 | (void)ent_src; | |
302 | return 1; | |
303 | } | |
304 | ||
305 | int 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 */ |