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