]>
Commit | Line | Data |
---|---|---|
101309bc PA |
1 | /* |
2 | * Copyright (c) 2012, Intel Corporation | |
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); | |
60 | ||
61 | /* Checking eflags to confirm cpuid instruction available */ | |
62 | /* Only necessary for 32 bit processors */ | |
63 | #if defined (__i386__) | |
64 | static int x86_has_eflag(uint32_t flag) | |
65 | { | |
66 | uint32_t f0, f1; | |
67 | asm("pushfl ; " | |
68 | "pushfl ; " | |
69 | "popl %0 ; " | |
70 | "movl %0,%1 ; " | |
71 | "xorl %2,%1 ; " | |
72 | "pushl %1 ; " | |
73 | "popfl ; " | |
74 | "pushfl ; " | |
75 | "popl %1 ; " | |
76 | "popfl" | |
77 | : "=&r" (f0), "=&r" (f1) | |
78 | : "ri" (flag)); | |
79 | return !!((f0^f1) & flag); | |
80 | } | |
81 | #endif | |
82 | ||
04361df2 | 83 | /* Calling cpuid instruction to verify rdrand and aes-ni capability */ |
101309bc PA |
84 | static void cpuid(unsigned int leaf, unsigned int subleaf, struct cpuid *out) |
85 | { | |
86 | #ifdef __i386__ | |
87 | /* %ebx is a forbidden register if we compile with -fPIC or -fPIE */ | |
88 | asm volatile("movl %%ebx,%0 ; cpuid ; xchgl %%ebx,%0" | |
89 | : "=r" (out->ebx), | |
90 | "=a" (out->eax), | |
91 | "=c" (out->ecx), | |
92 | "=d" (out->edx) | |
93 | : "a" (leaf), "c" (subleaf)); | |
94 | #else | |
95 | asm volatile("cpuid" | |
96 | : "=b" (out->ebx), | |
97 | "=a" (out->eax), | |
98 | "=c" (out->ecx), | |
99 | "=d" (out->edx) | |
100 | : "a" (leaf), "c" (subleaf)); | |
101 | #endif | |
102 | } | |
103 | ||
932e25b2 PA |
104 | /* Read data from the drng in chunks of 128 bytes for AES scrambling */ |
105 | #define CHUNK_SIZE (16*8) | |
106 | ||
107 | static unsigned char iv_buf[CHUNK_SIZE] __attribute__((aligned(128))); | |
04361df2 JM |
108 | static int have_aesni= 0; |
109 | ||
110 | /* Necessary if we have RDRAND but not AES-NI */ | |
111 | ||
112 | #ifdef HAVE_LIBGCRYPT | |
113 | ||
114 | #define MIN_GCRYPT_VERSION "1.0.0" | |
115 | ||
116 | static gcry_cipher_hd_t gcry_cipher_hd; | |
117 | ||
118 | /* Arbitrary 128-bit AES key 0x00102030405060708090A0B0C0D0E0F0 */ | |
119 | ||
120 | static const unsigned char key[16]= { | |
121 | 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, | |
122 | 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0 | |
123 | }; | |
124 | ||
125 | #endif | |
126 | ||
932e25b2 | 127 | |
101309bc PA |
128 | int xread_drng(void *buf, size_t size, struct rng *ent_src) |
129 | { | |
932e25b2 PA |
130 | char *p = buf; |
131 | size_t chunk; | |
132 | const int rdrand_round_count = 512; | |
133 | unsigned char tmp[CHUNK_SIZE] __attribute__((aligned(128))); | |
101309bc PA |
134 | int i; |
135 | ||
932e25b2 PA |
136 | while (size) { |
137 | for (i = 0; i < rdrand_round_count; i++) { | |
138 | if (!x86_rdrand_nlong(tmp, CHUNK_SIZE/sizeof(long))) { | |
139 | message(LOG_DAEMON|LOG_ERR, "read error\n"); | |
140 | return -1; | |
101309bc | 141 | } |
04361df2 JM |
142 | |
143 | // Use 128-bit AES in CBC mode to mangle our random data | |
144 | ||
145 | if ( have_aesni ) x86_aes_mangle(tmp, iv_buf); | |
146 | else { | |
147 | #ifdef HAVE_LIBGCRYPT | |
148 | gcry_error_t gcry_error; | |
149 | ||
150 | /* Encrypt tmp in-place. */ | |
151 | ||
152 | gcry_error= gcry_cipher_encrypt(gcry_cipher_hd, | |
153 | tmp, CHUNK_SIZE, 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 | #else | |
162 | return -1; | |
163 | #endif | |
164 | } | |
101309bc | 165 | } |
932e25b2 PA |
166 | chunk = (sizeof(tmp) > size) ? size : sizeof(tmp); |
167 | memcpy(p, tmp, chunk); | |
168 | p += chunk; | |
169 | size -= chunk; | |
101309bc PA |
170 | } |
171 | ||
101309bc PA |
172 | return 0; |
173 | } | |
174 | ||
175 | /* | |
176 | * Confirm RDRAND capabilities for drng entropy source | |
177 | */ | |
178 | int init_drng_entropy_source(struct rng *ent_src) | |
179 | { | |
180 | struct cpuid info; | |
04361df2 JM |
181 | /* We need RDRAND, but AESni is optional */ |
182 | const uint32_t features_ecx1_rdrand = 1 << 30; | |
183 | const uint32_t features_ecx1_aesni = 1 << 25; | |
101309bc PA |
184 | |
185 | #if defined(__i386__) | |
186 | if (!x86_has_eflag(1 << 21)) | |
187 | return 1; /* No CPUID instruction */ | |
188 | #endif | |
189 | ||
190 | cpuid(0, 0, &info); | |
191 | if (info.eax < 1) | |
192 | return 1; | |
193 | cpuid(1, 0, &info); | |
04361df2 | 194 | if (! (info.ecx & features_ecx1_rdrand) ) |
101309bc PA |
195 | return 1; |
196 | ||
04361df2 JM |
197 | have_aesni= (info.ecx & features_ecx1_aesni) ? 1 : 0; |
198 | #ifndef HAVE_LIBGCRYPT | |
199 | if ( ! have_aesni ) return 1; | |
200 | #endif | |
201 | ||
932e25b2 PA |
202 | /* Initialize the IV buffer */ |
203 | if (!x86_rdrand_nlong(iv_buf, CHUNK_SIZE/sizeof(long))) | |
204 | return 1; | |
205 | ||
04361df2 JM |
206 | #ifdef HAVE_LIBGCRYPT |
207 | if ( ! have_aesni ) { | |
208 | gcry_error_t gcry_error; | |
209 | ||
210 | if (! gcry_check_version(MIN_GCRYPT_VERSION) ) { | |
211 | message(LOG_DAEMON|LOG_ERR, | |
212 | "libgcrypt version mismatch: have %s, require >= %s\n", | |
213 | gcry_check_version(NULL), MIN_GCRYPT_VERSION); | |
214 | return 1; | |
215 | } | |
216 | ||
217 | gcry_error= gcry_cipher_open(&gcry_cipher_hd, | |
218 | GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, 0); | |
219 | ||
220 | if ( ! gcry_error ) { | |
221 | gcry_error= gcry_cipher_setkey(gcry_cipher_hd, key, 16); | |
222 | } | |
223 | ||
224 | if ( ! gcry_error ) { | |
225 | /* | |
226 | * Only need the first 16 bytes of iv_buf. AES-NI can | |
227 | * encrypt multiple blocks in parallel but we can't. | |
228 | */ | |
229 | ||
230 | gcry_error= gcry_cipher_setiv(gcry_cipher_hd, iv_buf, 16); | |
231 | } | |
232 | ||
233 | if ( gcry_error ) { | |
234 | message(LOG_DAEMON|LOG_ERR, | |
235 | "could not set key or IV: %s\n", | |
236 | gcry_strerror(gcry_error)); | |
237 | gcry_cipher_close(gcry_cipher_hd); | |
238 | return 1; | |
239 | } | |
240 | } | |
241 | #endif | |
242 | ||
101309bc PA |
243 | src_list_add(ent_src); |
244 | /* Bootstrap FIPS tests */ | |
245 | ent_src->fipsctx = malloc(sizeof(fips_ctx_t)); | |
246 | fips_init(ent_src->fipsctx, 0); | |
247 | return 0; | |
248 | } | |
249 | ||
250 | #else /* Not i386 or x86-64 */ | |
251 | ||
252 | int init_drng_entropy_source(struct rng *ent_src) | |
253 | { | |
254 | (void)ent_src; | |
255 | return 1; | |
256 | } | |
257 | ||
258 | int xread_drng(void *buf, size_t size, struct rng *ent_src) | |
259 | { | |
260 | (void)buf; | |
261 | (void)size; | |
262 | (void)ent_src; | |
263 | ||
264 | return -1; | |
265 | } | |
266 | ||
267 | #endif /* Not i386 or x86-64 */ |