1/*
2 * Copyright (c) 1999-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/proc.h>
32#include <sys/errno.h>
33#include <sys/ioctl.h>
34#include <sys/conf.h>
35#include <sys/fcntl.h>
36#include <string.h>
37#include <miscfs/devfs/devfs.h>
38#include <kern/lock.h>
39#include <kern/clock.h>
40#include <sys/time.h>
41#include <sys/malloc.h>
42#include <sys/uio_internal.h>
43
44#include <dev/random/randomdev.h>
45#include <dev/random/YarrowCoreLib/include/yarrow.h>
46#include <libkern/crypto/sha1.h>
47
48#include <mach/mach_time.h>
49#include <machine/machine_routines.h>
50
51#define RANDOM_MAJOR  -1 /* let the kernel pick the device number */
52
53d_ioctl_t       random_ioctl;
54
55/*
56 * A struct describing which functions will get invoked for certain
57 * actions.
58 */
59static struct cdevsw random_cdevsw =
60{
61	random_open,		/* open */
62	random_close,		/* close */
63	random_read,		/* read */
64	random_write,		/* write */
65	random_ioctl,		/* ioctl */
66	(stop_fcn_t *)nulldev, /* stop */
67	(reset_fcn_t *)nulldev, /* reset */
68	NULL,				/* tty's */
69	eno_select,			/* select */
70	eno_mmap,			/* mmap */
71	eno_strat,			/* strategy */
72	eno_getc,			/* getc */
73	eno_putc,			/* putc */
74	0					/* type */
75};
76
77/* Used to detect whether we've already been initialized */
78static int gRandomInstalled = 0;
79static PrngRef gPrngRef;
80static int gRandomError = 1;
81static lck_grp_t *gYarrowGrp;
82static lck_attr_t *gYarrowAttr;
83static lck_grp_attr_t *gYarrowGrpAttr;
84static lck_mtx_t *gYarrowMutex = 0;
85
86void CheckReseed(void);
87
88#define RESEED_TICKS 50 /* how long a reseed operation can take */
89
90
91enum {kBSizeInBits = 160}; // MUST be a multiple of 32!!!
92enum {kBSizeInBytes = kBSizeInBits / 8};
93typedef u_int32_t BlockWord;
94enum {kWordSizeInBits = 32};
95enum {kBSize = 5};
96typedef BlockWord Block[kBSize];
97
98/* define prototypes to keep the compiler happy... */
99
100void add_blocks(Block a, Block b, BlockWord carry);
101void fips_initialize(void);
102void random_block(Block b, int addOptional);
103u_int32_t CalculateCRC(u_int8_t* buffer, size_t length);
104
105/*
106 * Get 120 bits from yarrow
107 */
108
109/*
110 * add block b to block a
111 */
112void
113add_blocks(Block a, Block b, BlockWord carry)
114{
115	int i = kBSize;
116	while (--i >= 0)
117	{
118		u_int64_t c = (u_int64_t)carry +
119					  (u_int64_t)a[i] +
120					  (u_int64_t)b[i];
121		a[i] = c & ((1LL << kWordSizeInBits) - 1);
122		carry = c >> kWordSizeInBits;
123	}
124}
125
126
127
128struct sha1_ctxt g_sha1_ctx;
129char zeros[(512 - kBSizeInBits) / 8];
130Block g_xkey;
131Block g_random_data;
132int g_bytes_used;
133unsigned char g_SelfTestInitialized = 0;
134u_int32_t gLastBlockChecksum;
135
136static const u_int32_t g_crc_table[] =
137{
138	0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
139	0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
140	0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
141	0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
142	0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
143	0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
144	0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
145	0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
146	0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
147	0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
148	0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
149	0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
150	0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
151	0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
152	0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
153	0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
154	0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
155	0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
156	0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
157	0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
158	0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
159	0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
160	0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
161	0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
162	0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
163	0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
164	0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
165	0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
166	0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
167	0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
168	0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
169	0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
170};
171
172/*
173 * Setup for fips compliance
174 */
175
176/*
177 * calculate a crc-32 checksum
178 */
179u_int32_t CalculateCRC(u_int8_t* buffer, size_t length)
180{
181	u_int32_t crc = 0;
182
183	size_t i;
184	for (i = 0; i < length; ++i)
185	{
186		u_int32_t temp = (crc ^ ((u_int32_t) buffer[i])) & 0xFF;
187		crc = (crc >> 8) ^ g_crc_table[temp];
188	}
189
190	return crc;
191}
192
193/*
194 * get a random block of data per fips 186-2
195 */
196void
197random_block(Block b, int addOptional)
198{
199	int repeatCount = 0;
200	do
201	{
202		// do one iteration
203
204		if (addOptional)
205		{
206			Block xSeed;
207			prngOutput (gPrngRef, (BYTE*) &xSeed, sizeof (xSeed));
208
209			// add the seed to the previous value of g_xkey
210			add_blocks (g_xkey, xSeed, 0);
211		}
212
213		// compute "G"
214		SHA1Update (&g_sha1_ctx, (const u_int8_t *) &g_xkey, sizeof (g_xkey));
215
216		// add zeros to fill the internal SHA-1 buffer
217		SHA1Update (&g_sha1_ctx, (const u_int8_t *)zeros, sizeof (zeros));
218
219		// write the resulting block
220		memmove(b, g_sha1_ctx.h.b8, sizeof (Block));
221
222		// calculate the CRC-32 of the block
223		u_int32_t new_crc = CalculateCRC(g_sha1_ctx.h.b8, sizeof (Block));
224
225		// make sure we don't repeat
226		int cmp = new_crc == gLastBlockChecksum;
227		gLastBlockChecksum = new_crc;
228		if (!g_SelfTestInitialized)
229		{
230			g_SelfTestInitialized = 1;
231			return;
232		}
233		else if (!cmp)
234		{
235			return;
236		}
237
238		repeatCount += 1;
239
240		// fix up the next value of g_xkey
241		add_blocks (g_xkey, b, 1);
242	} while (repeatCount < 2);
243
244	/*
245	 * If we got here, three sucessive checksums of the random number
246	 * generator have been the same.  Since the odds of this happening are
247	 * 1 in 18,446,744,073,709,551,616, (1 in 18 quintillion) one of the following has
248	 * most likely happened:
249	 *
250	 * 1: There is a significant bug in this code.
251	 * 2: There has been a massive system failure.
252	 * 3: The universe has ceased to exist.
253	 *
254	 * There is no good way to recover from any of these cases. We
255	 * therefore panic.
256	 */
257
258	 panic("FIPS random self-test failed.");
259}
260
261/*
262 *Initialize ONLY the Yarrow generator.
263 */
264void
265PreliminarySetup(void)
266{
267    prng_error_status perr;
268
269    /* create a Yarrow object */
270    perr = prngInitialize(&gPrngRef);
271    if (perr != 0) {
272        printf ("Couldn't initialize Yarrow, /dev/random will not work.\n");
273        return;
274    }
275
276	/* clear the error flag, reads and write should then work */
277    gRandomError = 0;
278
279   {
280    struct timeval tt;
281    char buffer [16];
282
283    /* get a little non-deterministic data as an initial seed. */
284    microtime(&tt);
285
286    /*
287	 * So how much of the system clock is entropic?
288	 * It's hard to say, but assume that at least the
289	 * least significant byte of a 64 bit structure
290	 * is entropic.  It's probably more, how can you figure
291	 * the exact time the user turned the computer on, for example.
292    */
293    perr = prngInput(gPrngRef, (BYTE*) &tt, sizeof (tt), SYSTEM_SOURCE, 8);
294    if (perr != 0) {
295        /* an error, complain */
296        printf ("Couldn't seed Yarrow.\n");
297        return;
298    }
299
300    /* turn the data around */
301    perr = prngOutput(gPrngRef, (BYTE*) buffer, sizeof (buffer));
302
303    /* and scramble it some more */
304    perr = prngForceReseed(gPrngRef, RESEED_TICKS);
305    }
306
307    /* make a mutex to control access */
308    gYarrowGrpAttr = lck_grp_attr_alloc_init();
309    gYarrowGrp     = lck_grp_alloc_init("random", gYarrowGrpAttr);
310    gYarrowAttr    = lck_attr_alloc_init();
311    gYarrowMutex   = lck_mtx_alloc_init(gYarrowGrp, gYarrowAttr);
312
313	fips_initialize ();
314}
315
316const Block kKnownAnswer = {0x92b404e5, 0x56588ced, 0x6c1acd4e, 0xbf053f68, 0x9f73a93};
317
318void
319fips_initialize(void)
320{
321	/* So that we can do the self test, set the seed to zero */
322	memset(&g_xkey, 0, sizeof(g_xkey));
323
324	/* initialize our SHA1 generator */
325	SHA1Init (&g_sha1_ctx);
326
327	/* other initializations */
328	memset (zeros, 0, sizeof (zeros));
329	g_bytes_used = 0;
330	random_block(g_random_data, FALSE);
331
332	// check here to see if we got the initial data we were expecting
333	int i;
334	for (i = 0; i < kBSize; ++i)
335	{
336		if (kKnownAnswer[i] != g_random_data[i])
337		{
338			panic("FIPS random self test failed");
339		}
340	}
341
342	// now do the random block again to make sure that userland doesn't get predicatable data
343	random_block(g_random_data, TRUE);
344}
345
346/*
347 * Called to initialize our device,
348 * and to register ourselves with devfs
349 */
350void
351random_init(void)
352{
353	int ret;
354
355	if (gRandomInstalled)
356		return;
357
358	/* install us in the file system */
359	gRandomInstalled = 1;
360
361#ifndef ARM_BOARD_CONFIG_S5L8900XFPGA_1136JFS
362	/* setup yarrow and the mutex */
363	PreliminarySetup();
364#endif
365
366	ret = cdevsw_add(RANDOM_MAJOR, &random_cdevsw);
367	if (ret < 0) {
368		printf("random_init: failed to allocate a major number!\n");
369		gRandomInstalled = 0;
370		return;
371	}
372
373	devfs_make_node(makedev (ret, 0), DEVFS_CHAR,
374		UID_ROOT, GID_WHEEL, 0666, "random", 0);
375
376	/*
377	 * also make urandom
378	 * (which is exactly the same thing in our context)
379	 */
380	devfs_make_node(makedev (ret, 1), DEVFS_CHAR,
381		UID_ROOT, GID_WHEEL, 0666, "urandom", 0);
382}
383
384int
385random_ioctl(	__unused dev_t dev, u_long cmd, __unused caddr_t data,
386				__unused int flag, __unused struct proc *p  )
387{
388	switch (cmd) {
389	case FIONBIO:
390	case FIOASYNC:
391		break;
392	default:
393		return ENODEV;
394	}
395
396	return (0);
397}
398
399/*
400 * Open the device.  Make sure init happened, and make sure the caller is
401 * authorized.
402 */
403
404int
405random_open(__unused dev_t dev, int flags, __unused int devtype, __unused struct proc *p)
406{
407	if (gRandomError != 0) {
408		/* forget it, yarrow didn't come up */
409		return (ENOTSUP);
410	}
411
412	/*
413	 * if we are being opened for write,
414	 * make sure that we have privledges do so
415	 */
416	if (flags & FWRITE) {
417		if (securelevel >= 2)
418			return (EPERM);
419#ifndef __APPLE__
420		if ((securelevel >= 1) && proc_suser(p))
421			return (EPERM);
422#endif	/* !__APPLE__ */
423	}
424
425	return (0);
426}
427
428
429/*
430 * close the device.
431 */
432
433int
434random_close(__unused dev_t dev, __unused int flags, __unused int mode, __unused struct proc *p)
435{
436	return (0);
437}
438
439
440/*
441 * Get entropic data from the Security Server, and use it to reseed the
442 * prng.
443 */
444int
445random_write (__unused dev_t dev, struct uio *uio, __unused int ioflag)
446{
447    int retCode = 0;
448    char rdBuffer[256];
449
450    if (gRandomError != 0) {
451        return (ENOTSUP);
452    }
453
454    /* get control of the Yarrow instance, Yarrow is NOT thread safe */
455    lck_mtx_lock(gYarrowMutex);
456
457    /* Security server is sending us entropy */
458
459    while (uio_resid(uio) > 0 && retCode == 0) {
460        /* get the user's data */
461        // LP64todo - fix this!  uio_resid may be 64-bit value
462        int bytesToInput = min(uio_resid(uio), sizeof (rdBuffer));
463        retCode = uiomove(rdBuffer, bytesToInput, uio);
464        if (retCode != 0)
465            goto /*ugh*/ error_exit;
466
467        /* put it in Yarrow */
468        if (prngInput(gPrngRef, (BYTE*) rdBuffer,
469			bytesToInput, SYSTEM_SOURCE,
470        	bytesToInput * 8) != 0) {
471            retCode = EIO;
472            goto error_exit;
473        }
474    }
475
476    /* force a reseed */
477    if (prngForceReseed(gPrngRef, RESEED_TICKS) != 0) {
478        retCode = EIO;
479        goto error_exit;
480    }
481
482    /* retCode should be 0 at this point */
483
484error_exit: /* do this to make sure the mutex unlocks. */
485    lck_mtx_unlock(gYarrowMutex);
486    return (retCode);
487}
488
489/*
490 * return data to the caller.  Results unpredictable.
491 */
492int
493random_read(__unused dev_t dev, struct uio *uio, __unused int ioflag)
494{
495    int retCode = 0;
496
497    if (gRandomError != 0)
498        return (ENOTSUP);
499
500   /* lock down the mutex */
501    lck_mtx_lock(gYarrowMutex);
502
503    CheckReseed();
504	int bytes_remaining = uio_resid(uio);
505    while (bytes_remaining > 0 && retCode == 0) {
506        /* get the user's data */
507		int bytes_to_read = 0;
508
509		int bytes_available = kBSizeInBytes - g_bytes_used;
510        if (bytes_available == 0)
511		{
512			random_block(g_random_data, TRUE);
513			g_bytes_used = 0;
514			bytes_available = kBSizeInBytes;
515		}
516
517		bytes_to_read = min (bytes_remaining, bytes_available);
518
519        retCode = uiomove(((caddr_t)g_random_data)+ g_bytes_used, bytes_to_read, uio);
520        g_bytes_used += bytes_to_read;
521
522        if (retCode != 0)
523            goto error_exit;
524
525		bytes_remaining = uio_resid(uio);
526    }
527
528    retCode = 0;
529
530error_exit:
531    lck_mtx_unlock(gYarrowMutex);
532    return retCode;
533}
534
535/* export good random numbers to the rest of the kernel */
536void
537read_random(void* buffer, u_int numbytes)
538{
539    if (gYarrowMutex == 0) { /* are we initialized? */
540#ifndef ARM_BOARD_CONFIG_S5L8900XFPGA_1136JFS
541        PreliminarySetup ();
542#endif
543    }
544
545    lck_mtx_lock(gYarrowMutex);
546    CheckReseed();
547
548	int bytes_read = 0;
549
550	int bytes_remaining = numbytes;
551    while (bytes_remaining > 0) {
552        int bytes_to_read = min(bytes_remaining, kBSizeInBytes - g_bytes_used);
553        if (bytes_to_read == 0)
554		{
555			random_block(g_random_data, TRUE);
556			g_bytes_used = 0;
557			bytes_to_read = min(bytes_remaining, kBSizeInBytes);
558		}
559
560		memmove ((u_int8_t*) buffer + bytes_read, ((u_int8_t*)g_random_data)+ g_bytes_used, bytes_to_read);
561		g_bytes_used += bytes_to_read;
562		bytes_read += bytes_to_read;
563		bytes_remaining -= bytes_to_read;
564    }
565
566    lck_mtx_unlock(gYarrowMutex);
567}
568
569/*
570 * Return an unsigned long pseudo-random number.
571 */
572u_long
573RandomULong(void)
574{
575	u_long buf;
576	read_random(&buf, sizeof (buf));
577	return (buf);
578}
579
580void
581CheckReseed(void)
582{
583}
584