]> git.ipfire.org Git - thirdparty/rng-tools.git/blame - rngd_rdrand.c
Fix the AES keys so that they are correct and match the comments.
[thirdparty/rng-tools.git] / rngd_rdrand.c
CommitLineData
101309bc
PA
1/*
2 * Copyright (c) 2012, Intel Corporation
3 * Authors: Richard B. Hill <richard.b.hill@intel.com>,
4 * H. Peter Anvin <hpa@linux.intel.com>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18 *
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#if defined(__i386__) || defined(__x86_64__)
46
101309bc
PA
47/* Struct for CPUID return values */
48struct cpuid {
49 uint32_t eax, ecx, edx, ebx;
50};
51
52/* Get data from RDRAND */
53extern int x86_rdrand_nlong(void *ptr, size_t count);
54/* Conditioning RDRAND for seed-grade entropy */
55extern void x86_aes_mangle(void *data, void *state);
56
57/* Checking eflags to confirm cpuid instruction available */
58/* Only necessary for 32 bit processors */
59#if defined (__i386__)
60static int x86_has_eflag(uint32_t flag)
61{
62 uint32_t f0, f1;
63 asm("pushfl ; "
64 "pushfl ; "
65 "popl %0 ; "
66 "movl %0,%1 ; "
67 "xorl %2,%1 ; "
68 "pushl %1 ; "
69 "popfl ; "
70 "pushfl ; "
71 "popl %1 ; "
72 "popfl"
73 : "=&r" (f0), "=&r" (f1)
74 : "ri" (flag));
75 return !!((f0^f1) & flag);
76}
77#endif
78
79/* Calling cpuid instruction to verify rdrand capability */
80static void cpuid(unsigned int leaf, unsigned int subleaf, struct cpuid *out)
81{
82#ifdef __i386__
83 /* %ebx is a forbidden register if we compile with -fPIC or -fPIE */
84 asm volatile("movl %%ebx,%0 ; cpuid ; xchgl %%ebx,%0"
85 : "=r" (out->ebx),
86 "=a" (out->eax),
87 "=c" (out->ecx),
88 "=d" (out->edx)
89 : "a" (leaf), "c" (subleaf));
90#else
91 asm volatile("cpuid"
92 : "=b" (out->ebx),
93 "=a" (out->eax),
94 "=c" (out->ecx),
95 "=d" (out->edx)
96 : "a" (leaf), "c" (subleaf));
97#endif
98}
99
932e25b2
PA
100/* Read data from the drng in chunks of 128 bytes for AES scrambling */
101#define CHUNK_SIZE (16*8)
102
103static unsigned char iv_buf[CHUNK_SIZE] __attribute__((aligned(128)));
104
101309bc
PA
105int xread_drng(void *buf, size_t size, struct rng *ent_src)
106{
932e25b2
PA
107 char *p = buf;
108 size_t chunk;
109 const int rdrand_round_count = 512;
110 unsigned char tmp[CHUNK_SIZE] __attribute__((aligned(128)));
101309bc
PA
111 int i;
112
932e25b2
PA
113 while (size) {
114 for (i = 0; i < rdrand_round_count; i++) {
115 if (!x86_rdrand_nlong(tmp, CHUNK_SIZE/sizeof(long))) {
116 message(LOG_DAEMON|LOG_ERR, "read error\n");
117 return -1;
101309bc 118 }
932e25b2 119 x86_aes_mangle(tmp, iv_buf);
101309bc 120 }
932e25b2
PA
121 chunk = (sizeof(tmp) > size) ? size : sizeof(tmp);
122 memcpy(p, tmp, chunk);
123 p += chunk;
124 size -= chunk;
101309bc
PA
125 }
126
101309bc
PA
127 return 0;
128}
129
130/*
131 * Confirm RDRAND capabilities for drng entropy source
132 */
133int init_drng_entropy_source(struct rng *ent_src)
134{
135 struct cpuid info;
136 /* We need RDRAND and AESni */
137 const uint32_t need_features_ecx1 = (1 << 30) | (1 << 25);
138
139#if defined(__i386__)
140 if (!x86_has_eflag(1 << 21))
141 return 1; /* No CPUID instruction */
142#endif
143
144 cpuid(0, 0, &info);
145 if (info.eax < 1)
146 return 1;
147 cpuid(1, 0, &info);
148 if ((info.ecx & need_features_ecx1) != need_features_ecx1)
149 return 1;
150
932e25b2
PA
151 /* Initialize the IV buffer */
152 if (!x86_rdrand_nlong(iv_buf, CHUNK_SIZE/sizeof(long)))
153 return 1;
154
101309bc
PA
155 src_list_add(ent_src);
156 /* Bootstrap FIPS tests */
157 ent_src->fipsctx = malloc(sizeof(fips_ctx_t));
158 fips_init(ent_src->fipsctx, 0);
159 return 0;
160}
161
162#else /* Not i386 or x86-64 */
163
164int init_drng_entropy_source(struct rng *ent_src)
165{
166 (void)ent_src;
167 return 1;
168}
169
170int xread_drng(void *buf, size_t size, struct rng *ent_src)
171{
172 (void)buf;
173 (void)size;
174 (void)ent_src;
175
176 return -1;
177}
178
179#endif /* Not i386 or x86-64 */