1 /* $MirOS: src/sys/crypto/randcore.c,v 1.12 2014/02/20 00:57:23 tg Exp $ */
2
3 /*-
4 * Copyright © 2010, 2011, 2014
5 * Thorsten Glaser <tg@mirbsd.org>
6 *
7 * Provided that these terms and disclaimer and all copyright notices
8 * are retained or reproduced in an accompanying document, permission
9 * is granted to deal in this work without restriction, including un‐
10 * limited rights to use, publicly perform, distribute, sell, modify,
11 * merge, give away, or sublicence.
12 *
13 * This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
14 * the utmost extent permitted by applicable law, neither express nor
15 * implied; without malicious intent or gross negligence. In no event
16 * may a licensor, author or contributor be held liable for indirect,
17 * direct, other damage, loss, or other issues arising in any way out
18 * of dealing in the work, even if advised of the possibility of such
19 * damage or existence of a defect, except proven that it results out
20 * of said person’s immediate fault when using the work as intended.
21 *-
22 * This file contains the core random device implementation and stee‐
23 * ring point for the random subsystem in MirBSD. It also contains an
24 * implementation of the “lopool”, i.e. a hashed pool where userspace
25 * non-root processes and the kernel can send “untrusted” entropy to,
26 * which then is periodically “collapsed” into an arcfour state named
27 * lopool_collapse which in turn is used by arc4random_reinit when it
28 * stirs the main arcfour state used in arc4random(9).
29 */
30
31 #define IN_RANDOM_CORE
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/conf.h>
36 #include <sys/kernel.h>
37 #include <sys/timeout.h>
38 #include <crypto/randimpl.h>
39 #include <mirhash.h>
40
41 /* import from vers.c generated by conf/newvers.sh */
42 extern uint32_t _randseed;
43 /* only bytes actually changed by config(8) */
44 extern unsigned char initial_entropy[16];
45
46 struct rnd_pooladd {
47 union {
48 struct timeval tv;
49 #if defined(I586_CPU) || defined(I686_CPU)
50 unsigned long long tsc;
51 #endif
52 } u;
53 const void *sp, *dp;
54 size_t sz;
55 };
56
57 void rnd_lopool_dequeue(void *);
58
59 /*
60 * This variable secures the following things: rndpool (tytso code) is
61 * operational; timeouts for arc4random and lopool-collapse can be run;
62 * lopool-collapse arcfour state has been initialised
63 */
64 int rnd_attached = 0;
65
66 size_t lopool_content = 0;
67 uint32_t lopool_uhash[32];
68 uint8_t lopool_uptr = 0;
69
70 struct arcfour_status lopool_collapse;
71 struct timeout arc4random_timeout;
72 struct timeout rnd_lopool_timeout;
73
74 /*
75 * Backend routine for adding some bytes, together with pointer,
76 * size, stack, and timing information, into the hash lopool.
77 * We use the BAFH transformation only for folding the user-
78 * specified information into 32 BAFH states (128 bytes)
79 * and count the bytes we added. (rnd_lopool_addh adds an BAFH
80 * hash of the data, not the data itself.) Once the content is
81 * 128 bytes or more, rnd_lopool_dequeue collapses them into
82 * lopool_collapse where it will be picked up by the next run
83 * of the arc4random(9) stir function.
84 */
85 static void
rnd_pool_add(struct rnd_pooladd * sa,const void * d,size_t n)86 rnd_pool_add(struct rnd_pooladd *sa, const void *d, size_t n)
87 {
88 int s;
89
90 #if defined(I586_CPU) || defined(I686_CPU)
91 if (pentium_mhz) {
92 __asm __volatile("rdtsc" : "=A" (sa->u.tsc));
93 } else
94 #endif
95 {
96 /* cannot use memcpy since mono_time is volatile */
97 sa->u.tv.tv_sec = mono_time.tv_sec;
98 sa->u.tv.tv_usec = mono_time.tv_usec;
99 }
100 sa->sp = sa;
101
102 RNDEBUG(RD_HASHLOPOOL, "rnd: lopool += %lu(%lu) bytes\n",
103 (u_long)n, (u_long)sa->sz);
104
105 s = splhigh();
106 arc4random_roundhash(lopool_uhash, &lopool_uptr, sa, sizeof(*sa));
107 arc4random_roundhash(lopool_uhash, &lopool_uptr, d, n);
108 lopool_content += n;
109 rndstats.lopool_bytes += n;
110 ++rndstats.lopool_enq;
111 splx(s);
112 }
113
114 /*
115 * called from most of the initialisation code; historical because
116 * we used to be unable to run either lopool’s predecessor or
117 * arc4random itself early in the boot process; nowadays, this is
118 * merely a “big data” function, e.g. for the pre-start log message
119 * buffer, which may have leftovers from the last kernel, or some
120 * filesystem superblock or other data of few entropic value
121 */
122 void
rnd_lopool_addh(const void * vp,size_t n)123 rnd_lopool_addh(const void *vp, size_t n)
124 {
125 struct rnd_pooladd pa;
126 uint32_t h;
127
128 h = arc4random();
129 BAFHUpdateMem_reg(h, vp, n);
130 BAFHFinish_reg(h);
131
132 pa.dp = vp;
133 pa.sz = n;
134 rnd_pool_add(&pa, &h, sizeof(h));
135 }
136
137 /* these two directly add their argument into the lopool */
138
139 /* pointer and length, read data */
140 void
rnd_lopool_add(const void * buf,size_t len)141 rnd_lopool_add(const void *buf, size_t len)
142 {
143 struct rnd_pooladd pa;
144
145 pa.dp = buf;
146 pa.sz = len;
147 rnd_pool_add(&pa, buf, len);
148 }
149
150 /* integral argument, passed on the stack */
151 void
rnd_lopool_addv(unsigned long v)152 rnd_lopool_addv(unsigned long v)
153 {
154 struct rnd_pooladd pa;
155
156 pa.sz = 0;
157 rnd_pool_add(&pa, &v, sizeof(v));
158 }
159
160 #ifndef rnd_lopool_addvq
161 /* for use by the hardclockent routines: no RNDEBUG, no counting */
162 void
rnd_lopool_addvq(unsigned long v)163 rnd_lopool_addvq(unsigned long v)
164 {
165 int s;
166
167 s = splhigh();
168 arc4random_roundhash(lopool_uhash, &lopool_uptr, &v, sizeof(v));
169 splx(s);
170 }
171 #endif
172
173 /*
174 * This is the function called all 1‥3 seconds to collapse the
175 * lopool’s hash into its arcfour state if there was enough data.
176 */
177 void
rnd_lopool_dequeue(void * arg __unused)178 rnd_lopool_dequeue(void *arg __unused)
179 {
180 int s;
181 struct timeval tv[2];
182
183 s = splhigh();
184
185 if (!rnd_attached) {
186 RNDEBUG(RD_ALWAYS, "rnd: lopool dequeue before attach\n");
187 goto out;
188 }
189
190 /* if we were called directly instead of from timeout */
191 timeout_del(&rnd_lopool_timeout);
192
193 if (lopool_content >= 128) {
194 RNDEBUG(RD_ARC4LOPOOL, "rnd: lopool dequeues %lu bytes\n",
195 (u_long)lopool_content);
196
197 /* add current time (mono and TAI) first */
198 tv[0].tv_sec = mono_time.tv_sec;
199 tv[0].tv_usec = mono_time.tv_usec;
200 tv[1].tv_sec = time.tv_sec;
201 tv[1].tv_usec = time.tv_usec;
202 arc4random_roundhash(lopool_uhash, &lopool_uptr, tv,
203 sizeof(tv));
204
205 /* finalise all 32 one-at-a-time hashes */
206 for (lopool_uptr = 0; lopool_uptr < 32; ++lopool_uptr)
207 BAFHFinish_mem(lopool_uhash[lopool_uptr]);
208
209 /* stir the collapse pool with the result */
210 arcfour_ksa(&lopool_collapse, (void *)lopool_uhash,
211 sizeof(lopool_uhash));
212
213 /* assert(lopool_uptr == 32); */
214 while (lopool_uptr--)
215 /* re-initialise all 32 BAFH states from RNG */
216 lopool_uhash[lopool_uptr] = arc4random();
217
218 /* sync statistic data / counter */
219 lopool_content = 0;
220 lopool_uptr = 0;
221
222 /*
223 * note: we don't throw away the “early keystream” like
224 * with arc4random(9) because this is never used/exposed
225 * to anything save arc4random_reinit, and we don’t care
226 * about bias here either, this is just for distribution
227 */
228
229 ++rndstats.lopool_deq;
230 }
231
232 /* 1 + [0;2[ seconds */
233 timeout_add(&rnd_lopool_timeout, hz + arc4random_uniform(hz << 1));
234
235 out:
236 splx(s);
237 }
238
239
240 void
randomattach(void)241 randomattach(void)
242 {
243 if (rnd_attached) {
244 RNDEBUG(RD_ALWAYS, "random: second attach\n");
245 return;
246 }
247
248 timeout_set(&arc4random_timeout, arc4random_reinit, NULL);
249 timeout_set(&rnd_lopool_timeout, rnd_lopool_dequeue, NULL);
250
251 /* dev/rnd.c */
252 rndpool_init();
253
254 arcfour_init(&lopool_collapse);
255 /* this dword is where also locore.s writes to */
256 add_true_randomness(
257 ((uint32_t)initial_entropy[3] << 24) |
258 ((uint32_t)initial_entropy[2] << 16) |
259 ((uint32_t)initial_entropy[1] << 8) |
260 (uint32_t)initial_entropy[0]);
261 memcpy(initial_entropy, &_randseed, 4);
262 arcfour_ksa(&lopool_collapse, initial_entropy, 16);
263 /* just in case there’s something actually using these */
264 arc4random_buf(initial_entropy, 16);
265 _randseed = arc4random();
266
267 rnd_attached = 1;
268 /* initialises both lopool and arc4random timeouts */
269 rnd_flush();
270 }
271
272
273 /* called from RNDSTIRARC4 ioctl by pid 1, during boot and reboot */
274 void
rnd_flush(void)275 rnd_flush(void)
276 {
277 int s;
278
279 RNDEBUG(RD_ALWAYS, "rnd: flushing\n");
280 s = splhigh();
281 if (lopool_content < 128)
282 /* force rnd_lopool_dequeue() to act */
283 lopool_content = 128;
284 rnd_lopool_dequeue(NULL);
285 arc4random_reinit(NULL);
286 splx(s);
287 }
288