]>
git.ipfire.org Git - thirdparty/rng-tools.git/blob - rngd_entsource.c
9a37081141c9d62b3eeebbfd2e9a27cd9d6e8be0
2 * rngd_entsource.c -- Entropy source and conditioning
4 * Copyright (C) 2001 Philipp Rumpf
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.
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.
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
24 #error Invalid or missing autoconf build environment
27 #include "rng-tools-config.h"
32 #include <sys/types.h>
43 #include "rngd_entsource.h"
46 /* The overhead incured when tpm returns the random nos as per TCG spec
48 #define TPM_GET_RNG_OVERHEAD 14
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
)
66 : "=&r" (f0
), "=&r" (f1
)
68 return !!((f0
^f1
) & flag
);
72 /* Calling cpuid instruction to verify rdrand capability */
73 static void cpuid(unsigned int leaf
, unsigned int subleaf
, struct cpuid
*out
)
76 /* %ebx is a forbidden register if we compile with -fPIC or -fPIE */
77 asm volatile("movl %%ebx,%0 ; cpuid ; xchgl %%ebx,%0"
82 : "a" (leaf
), "c" (subleaf
));
89 : "a" (leaf
), "c" (subleaf
));
93 /* Read data from the entropy source */
94 int xread(void *buf
, size_t size
, struct rng
*ent_src
)
101 r
= read(ent_src
->rng_fd
, buf
+ off
, size
);
102 } while ((r
== -1) && (errno
== EINTR
));
110 message(LOG_DAEMON
|LOG_ERR
, "read error\n");
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)
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
)
128 int rdrand_round_count
= size
/ 128;
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)));
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))) {
142 if (!x86_rdrand_nlong(m_buf
, sizeof(m_buf
)/sizeof(long))) {
146 memcpy(tmp
, iv_buf
, IV_SIZE
);
147 memcpy(tmp
+IV_SIZE
, m_buf
, MSG_SIZE
);
149 x86_aes_mangle(tmp
, fwd
);
150 r
= (sizeof(tmp
) > size
)? size
: sizeof(tmp
);
154 memcpy(buf
+off
, tmp
, r
);
162 if (size
> 0 && size
< psize
) {
163 message(LOG_DAEMON
|LOG_ERR
, "read error\n");
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
)
174 size_t bytes_read
= 0;
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 */
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
);
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
);
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);
205 while (bytes_read
< size
) {
207 while (r
< sizeof(rng_cmd
)) {
208 retval
= write(ent_src
->rng_fd
,
210 sizeof(rng_cmd
) - r
);
212 message(LOG_ERR
|LOG_INFO
,
213 "Error writing %s\n",
220 if (r
< sizeof(rng_cmd
)) {
221 message(LOG_ERR
|LOG_INFO
,
222 "Error writing %s\n", ent_src
->rng_name
);
226 r
= read(ent_src
->rng_fd
, temp_buf
,size
);
227 r
= (r
- TPM_GET_RNG_OVERHEAD
);
229 message(LOG_ERR
|LOG_INFO
,
230 "Error reading from TPM, no entropy gathered");
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
));
240 memcpy(offset
, temp_buf
+ TPM_GET_RNG_OVERHEAD
, r
);
245 close(ent_src
->rng_fd
);
250 /* Initialize entropy source */
251 static int discard_initial_data(struct rng
*ent_src
)
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...
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
);
262 /* Return 32 bits of bootstrap data */
263 xread(tempbuf
, sizeof(tempbuf
), ent_src
);
265 return tempbuf
[0] | (tempbuf
[1] << 8) |
266 (tempbuf
[2] << 16) | (tempbuf
[3] << 24);
270 * Open entropy source, and initialize it
272 int init_entropy_source(struct rng
*ent_src
)
274 ent_src
->rng_fd
= open(ent_src
->rng_name
, O_RDONLY
);
275 if (ent_src
->rng_fd
== -1) {
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
));
286 * Confirm RDRAND capabilities for drng entropy source
288 int init_drng_entropy_source(struct rng
*ent_src
)
290 #if defined (__x86_64__) || defined(__i386__)
292 int got_intel_cpu
= 0;
294 #if defined (__i386__)
295 uint32_t flag
= 0x200000;
297 if(!x86_has_eflag(flag
)) return 1; //check 32 bit processor for cpuid
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) {
306 if(got_intel_cpu
== 0) return 1;
309 if ((info
.ecx
& 0x40000000)!=0x40000000) return 1;
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);
317 //No intel processor, no drng
323 * Open tpm entropy source, and initialize it
325 int init_tpm_entropy_source(struct rng
*ent_src
)
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
);
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
);