]> git.ipfire.org Git - thirdparty/rng-tools.git/blob - rngd_entsource.c
9a37081141c9d62b3eeebbfd2e9a27cd9d6e8be0
[thirdparty/rng-tools.git] / rngd_entsource.c
1 /*
2 * rngd_entsource.c -- Entropy source and conditioning
3 *
4 * Copyright (C) 2001 Philipp Rumpf
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #define _GNU_SOURCE
22
23 #ifndef HAVE_CONFIG_H
24 #error Invalid or missing autoconf build environment
25 #endif
26
27 #include "rng-tools-config.h"
28
29 #include <unistd.h>
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <syslog.h>
37 #include <string.h>
38 #include <stddef.h>
39
40 #include "rngd.h"
41 #include "fips.h"
42 #include "exits.h"
43 #include "rngd_entsource.h"
44
45
46 /* The overhead incured when tpm returns the random nos as per TCG spec
47 * it is 14 bytes.*/
48 #define TPM_GET_RNG_OVERHEAD 14
49
50 /* Checking eflags to confirm cpuid instruction available */
51 /* Only necessary for 32 bit processors */
52 #if defined (__i386__)
53 int x86_has_eflag(uint32_t flag)
54 {
55 uint32_t f0, f1;
56 asm("pushfl ; "
57 "pushfl ; "
58 "popl %0 ; "
59 "movl %0,%1 ; "
60 "xorl %2,%1 ; "
61 "pushl %1 ; "
62 "popfl ; "
63 "pushfl ; "
64 "popl %1 ; "
65 "popfl"
66 : "=&r" (f0), "=&r" (f1)
67 : "ri" (flag));
68 return !!((f0^f1) & flag);
69 }
70 #endif
71
72 /* Calling cpuid instruction to verify rdrand capability */
73 static void cpuid(unsigned int leaf, unsigned int subleaf, struct cpuid *out)
74 {
75 #ifdef __i386__
76 /* %ebx is a forbidden register if we compile with -fPIC or -fPIE */
77 asm volatile("movl %%ebx,%0 ; cpuid ; xchgl %%ebx,%0"
78 : "=r" (out->ebx),
79 "=a" (out->eax),
80 "=c" (out->ecx),
81 "=d" (out->edx)
82 : "a" (leaf), "c" (subleaf));
83 #else
84 asm volatile("cpuid"
85 : "=b" (out->ebx),
86 "=a" (out->eax),
87 "=c" (out->ecx),
88 "=d" (out->edx)
89 : "a" (leaf), "c" (subleaf));
90 #endif
91 }
92
93 /* Read data from the entropy source */
94 int xread(void *buf, size_t size, struct rng *ent_src)
95 {
96 size_t off = 0;
97 ssize_t r;
98
99 while (size > 0) {
100 do {
101 r = read(ent_src->rng_fd, buf + off, size);
102 } while ((r == -1) && (errno == EINTR));
103 if (r <= 0)
104 break;
105 off += r;
106 size -= r;
107 }
108
109 if (size) {
110 message(LOG_DAEMON|LOG_ERR, "read error\n");
111 return -1;
112 }
113 return 0;
114 }
115
116 /* Initialization vector and msg sizes for standard AES usage */
117 #define IV_SIZE (16*1)
118 #define MSG_SIZE (16*7)
119 #define CHUNK_SIZE (16*8)
120
121 /* Read data from the drng
122 * in chunks of 128 bytes for AES scrambling */
123 int xread_drng(void *buf, size_t size, struct rng *ent_src)
124 {
125 size_t psize = size;
126 size_t off = 0;
127 ssize_t r = 0;
128 int rdrand_round_count = size / 128;
129
130 static unsigned char iv_buf[IV_SIZE] __attribute__((aligned(128)));
131 static unsigned char m_buf[MSG_SIZE] __attribute__((aligned(128)));
132 static unsigned char tmp[CHUNK_SIZE] __attribute__((aligned(128)));
133 static unsigned char fwd[CHUNK_SIZE] __attribute__((aligned(128)));
134 int i;
135
136 while (size > 0 && size <= psize) {
137 for (i = 0; i < rdrand_round_count && size <= psize; i++) {
138 if (!x86_rdrand_nlong(iv_buf, sizeof(iv_buf)/sizeof(long))) {
139 r = -1;
140 break;
141 }
142 if (!x86_rdrand_nlong(m_buf, sizeof(m_buf)/sizeof(long))) {
143 r = -1;
144 break;
145 }
146 memcpy(tmp, iv_buf, IV_SIZE);
147 memcpy(tmp+IV_SIZE, m_buf, MSG_SIZE);
148
149 x86_aes_mangle(tmp, fwd);
150 r = (sizeof(tmp) > size)? size : sizeof(tmp);
151
152 if (r <= 0)
153 break;
154 memcpy(buf+off, tmp, r);
155 off += r;
156 size -= r;
157 }
158 if (r <= 0)
159 break;
160 }
161
162 if (size > 0 && size < psize) {
163 message(LOG_DAEMON|LOG_ERR, "read error\n");
164 return -1;
165 }
166 return 0;
167 }
168
169 /* tpm rng read call to kernel has 13 bytes of overhead
170 * the logic to process this involves reading to a temporary_buf
171 * and copying the no generated to buf */
172 int xread_tpm(void *buf, size_t size, struct rng *ent_src)
173 {
174 size_t bytes_read = 0;
175 ssize_t r;
176 int retval;
177 unsigned char *temp_buf = NULL;
178 unsigned char rng_cmd[] = {
179 0, 193, /* TPM_TAG_RQU_COMMAND */
180 0, 0, 0, 14, /* length */
181 0, 0, 0, 70, /* TPM_ORD_GetRandom */
182 0, 0, 0, 0, /* number of bytes to return */
183 };
184 char *offset;
185
186 ent_src->rng_fd = open(ent_src->rng_name, O_RDWR);
187 if (ent_src->rng_fd == -1) {
188 message(LOG_ERR|LOG_INFO,"Unable to open file: %s",ent_src->rng_name);
189 return -1;
190 }
191
192 temp_buf = (unsigned char *) malloc(size + TPM_GET_RNG_OVERHEAD);
193 memset(temp_buf, 0, (size+TPM_GET_RNG_OVERHEAD));
194 if (temp_buf == NULL) {
195 message(LOG_ERR|LOG_INFO,"No memory");
196 close(ent_src->rng_fd);
197 return -1;
198 }
199 /* 32 bits has been reserved for random byte size */
200 rng_cmd[13] = (unsigned char)(size & 0xFF);
201 rng_cmd[12] = (unsigned char)((size >> 8) & 0xFF);
202 rng_cmd[11] = (unsigned char)((size >> 16) & 0xFF);
203 rng_cmd[10] = (unsigned char)((size >> 24) & 0xFF);
204 offset = buf;
205 while (bytes_read < size) {
206 r=0;
207 while (r < sizeof(rng_cmd)) {
208 retval = write(ent_src->rng_fd,
209 rng_cmd + r,
210 sizeof(rng_cmd) - r);
211 if (retval < 0) {
212 message(LOG_ERR|LOG_INFO,
213 "Error writing %s\n",
214 ent_src->rng_name);
215 retval = -1;
216 goto error_out;
217 }
218 r += retval;
219 }
220 if (r < sizeof(rng_cmd)) {
221 message(LOG_ERR|LOG_INFO,
222 "Error writing %s\n", ent_src->rng_name);
223 retval = -1;
224 goto error_out;
225 }
226 r = read(ent_src->rng_fd, temp_buf,size);
227 r = (r - TPM_GET_RNG_OVERHEAD);
228 if(r <= 0) {
229 message(LOG_ERR|LOG_INFO,
230 "Error reading from TPM, no entropy gathered");
231 retval = -1;
232 goto error_out;
233 }
234 bytes_read = bytes_read + r;
235 if (bytes_read > size) {
236 memcpy(offset,temp_buf + TPM_GET_RNG_OVERHEAD,
237 r - (bytes_read - size));
238 break;
239 }
240 memcpy(offset, temp_buf + TPM_GET_RNG_OVERHEAD, r);
241 offset = offset + r;
242 }
243 retval = 0;
244 error_out:
245 close(ent_src->rng_fd);
246 free(temp_buf);
247 return retval;
248 }
249
250 /* Initialize entropy source */
251 static int discard_initial_data(struct rng *ent_src)
252 {
253 /* Trash 32 bits of what is probably stale (non-random)
254 * initial state from the RNG. For Intel's, 8 bits would
255 * be enough, but since AMD's generates 32 bits at a time...
256 *
257 * The kernel drivers should be doing this at device powerup,
258 * but at least up to 2.4.24, it doesn't. */
259 unsigned char tempbuf[4];
260 xread(tempbuf, sizeof(tempbuf), ent_src);
261
262 /* Return 32 bits of bootstrap data */
263 xread(tempbuf, sizeof(tempbuf), ent_src);
264
265 return tempbuf[0] | (tempbuf[1] << 8) |
266 (tempbuf[2] << 16) | (tempbuf[3] << 24);
267 }
268
269 /*
270 * Open entropy source, and initialize it
271 */
272 int init_entropy_source(struct rng *ent_src)
273 {
274 ent_src->rng_fd = open(ent_src->rng_name, O_RDONLY);
275 if (ent_src->rng_fd == -1) {
276 return 1;
277 }
278 src_list_add(ent_src);
279 /* Bootstrap FIPS tests */
280 ent_src->fipsctx = malloc(sizeof(fips_ctx_t));
281 fips_init(ent_src->fipsctx, discard_initial_data(ent_src));
282 return 0;
283 }
284
285 /*
286 * Confirm RDRAND capabilities for drng entropy source
287 */
288 int init_drng_entropy_source(struct rng *ent_src)
289 {
290 #if defined (__x86_64__) || defined(__i386__)
291 struct cpuid info;
292 int got_intel_cpu = 0;
293
294 #if defined (__i386__)
295 uint32_t flag = 0x200000;
296
297 if(!x86_has_eflag(flag)) return 1; //check 32 bit processor for cpuid
298 #endif
299
300 cpuid(0,0, &info);
301 if(memcmp((char *)(&info.ebx), "Genu", 4) == 0 &&
302 memcmp((char *)(&info.edx), "ineI", 4) == 0 &&
303 memcmp((char *)(&info.ecx), "ntel", 4) == 0) {
304 got_intel_cpu = 1;
305 }
306 if(got_intel_cpu == 0) return 1;
307
308 cpuid(1,0,&info);
309 if ((info.ecx & 0x40000000)!=0x40000000) return 1;
310
311 src_list_add(ent_src);
312 /* Bootstrap FIPS tests */
313 ent_src->fipsctx = malloc(sizeof(fips_ctx_t));
314 fips_init(ent_src->fipsctx, 0);
315 return 0;
316 #else
317 //No intel processor, no drng
318 return 1;
319 #endif
320 }
321
322 /*
323 * Open tpm entropy source, and initialize it
324 */
325 int init_tpm_entropy_source(struct rng *ent_src)
326 {
327 ent_src->rng_fd = open(ent_src->rng_name, O_RDWR);
328 if (ent_src->rng_fd == -1) {
329 message(LOG_ERR|LOG_INFO,"Unable to open file: %s",ent_src->rng_name);
330 return 1;
331 }
332 src_list_add(ent_src);
333 /* Bootstrap FIPS tests */
334 ent_src->fipsctx = malloc(sizeof(fips_ctx_t));
335 fips_init(ent_src->fipsctx, 0);
336 close(ent_src->rng_fd);
337 return 0;
338 }