From c24a95b8191266d33a7b1b13d142f49584347fa4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josef=20S=C3=B6ntgen?= <josef.soentgen@genode-labs.com>
Date: Thu, 4 Oct 2012 17:28:54 +0200
Subject: [PATCH] Noux: add random_file_system

The random file-system provides an arc4 based urandom implementation
which is needed for OpenSSL.

NOTE: the Arc4random class currently _does not collect enough_ random
bytes!
---
 ports/src/noux/dir_file_system.h    |   7 +
 ports/src/noux/random_file_system.h | 407 ++++++++++++++++++++++++++++
 2 files changed, 414 insertions(+)
 create mode 100644 ports/src/noux/random_file_system.h

diff --git a/ports/src/noux/dir_file_system.h b/ports/src/noux/dir_file_system.h
index 7699c242c5..8b1722018e 100644
--- a/ports/src/noux/dir_file_system.h
+++ b/ports/src/noux/dir_file_system.h
@@ -26,6 +26,8 @@
 #include <null_file_system.h>
 #include <zero_file_system.h>
 #include <stdio_file_system.h>
+#include <random_file_system.h>
+
 
 namespace Noux {
 
@@ -116,6 +118,11 @@ namespace Noux {
 						continue;
 					}
 
+					if (sub_node.has_type("random")) {
+						_append_file_system(new Random_file_system(0, 0));
+						continue;
+					}
+
 					{
 						char type_name[64];
 						sub_node.type_name(type_name, sizeof(type_name));
diff --git a/ports/src/noux/random_file_system.h b/ports/src/noux/random_file_system.h
new file mode 100644
index 0000000000..f023d18940
--- /dev/null
+++ b/ports/src/noux/random_file_system.h
@@ -0,0 +1,407 @@
+/*
+ * \brief  Device Random filesystem
+ * \author Josef Soentgen
+ * \date   2012-07-31
+ */
+
+/*
+ * Copyright (C) 2012 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#ifndef _NOUX__RANDOM_FILE_SYSTEM_H_
+#define _NOUX__RANDOM_FILE_SYSTEM_H_
+
+/* Genode includes */
+#include <base/printf.h>
+#include <base/stdint.h>
+#include <util/string.h>
+
+/* Noux includes */
+#include <noux_session/sysio.h>
+#include "file_system.h"
+
+/*-
+ * Copyright (c) 2010, 2012
+ *      Thorsten Glaser <tg@mirbsd.org>
+ * Copyright (c) 2012
+ *      Josef Soentgen <cnuke@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ *-
+ * arc4random for use as NOUX random device.
+ *
+ * From:
+ * MirOS: src/kern/c/arcfour_base.c,v 1.1 2010/09/12 17:10:49 tg Exp
+ * MirOS: src/kern/c/arcfour_ksa.c,v 1.1 2010/09/12 17:10:50 tg Exp
+ * MirOS: src/lib/libc/crypt/arc4random_base.c,v 1.4 2011/07/06 22:22:09 tg Exp
+ * MirOS: src/lib/libc/crypt/arc4random_buf.c,v 1.1 2010/09/12 17:10:53 tg Exp
+ */
+
+
+namespace Noux {
+
+	using namespace Genode;
+
+	/**
+	 * Arcfour cipher re-implementation from (alledged) spec description.
+	 */
+
+	class Arc4random
+	{
+		private:
+
+			uint8_t S[256];
+			uint8_t i;
+			uint8_t j;
+			uint16_t num;
+			uint8_t initialised;
+
+			/*
+			 * Base cipher operation: initialise state
+			 */
+			void init(void)
+			{
+				register uint8_t n = 0;
+
+				do {
+					S[n] = n;
+				} while (++n);
+
+				i = j = 0;
+			}
+
+			/*
+			 * Base cipher operation: get byte of keystream.
+			 */
+			uint8_t byte(void)
+			{
+				register uint8_t si, sj;
+
+				si = S[++i];
+				j += si;
+				sj = S[j];
+				S[i] = sj;
+				S[j] = si;
+				return (S[(uint8_t)(si + sj)]);
+			}
+
+			/*
+			 * Normal key scheduling algorithm.
+			 */
+			void ksa(const uint8_t *key, size_t keylen)
+			{
+				register uint8_t si, n = 0;
+
+				--i;
+				do {
+					++i;
+					si = S[i];
+					j = (uint8_t)(j + si + key[n++ % keylen]);
+					S[i] = S[j];
+					S[j] = si;
+				} while (n);
+				j = ++i;
+			}
+
+			/*
+			 * arc4random implementation
+			 */
+			void stir_unlocked(void)
+			{
+				register unsigned int m;
+				uint8_t n;
+				struct {
+					//	struct timeval tv;
+					//	pid_t mypid;
+					uint32_t mypid;
+					const void *stkptr, *bssptr, *txtptr;
+					uint16_t num;
+					uint8_t initialised;
+					// FIXME sizeof (sb) should be as close to 256 as possible
+				} sb;
+
+				/* save some state; while not a secret, helps through variety */
+				//sb.mypid = getpid();
+				sb.mypid = 42;
+				sb.stkptr = &sb;
+				sb.bssptr = &i;
+				//sb.txtptr = &byte;
+				sb.txtptr = (const void *)0xDEADBEEF;;
+				sb.num = num;
+				sb.initialised = initialised;
+
+				/* initialise i, j and the S-box if not done yet */
+				if (!initialised) {
+					init();
+					initialised = 1;
+				}
+
+				// FIXME initialize more sb member
+
+				/* dance around by some bytes for added protection */
+				n = byte();
+				/* and carry some over to below */
+				m = byte();
+				while (n--)
+					(void)byte();
+				m += byte();
+
+				/* while time is not a secret, it helps through variety */
+				//gettimeofday(&sb.tv, NULL);
+
+				/* actually add the hopefully random-containing seed */
+				ksa((const uint8_t *)&sb, sizeof(sb));
+
+				/* throw away the first part of the arcfour keystream */
+				/* with some bytes varied for added protection */
+				m += 256 * 4 + (byte() & 0x1F);
+				while (m--)
+					(void)byte();
+				/* state is now good for so many bytes: (not so much in NOUX) */
+				num = 2000;
+			}
+
+			void buf(void *buf_, size_t len)
+			{
+				size_t chunk;
+				uint8_t *buf = (uint8_t *)buf_;
+				uint8_t m, n;
+
+				/* operate in chunks of at most 256 bytes */
+				while ((chunk = len > 256 ? 256 : len) > 0) {
+					/* adjust len */
+					len -= chunk;
+
+					/* is the state good for this? (or even initialised, yet?) */
+					if (num < chunk)
+						stir_unlocked();
+
+					/* dance around a few bytes for added protection */
+					m = byte() & 3;
+					/* and carry some down below */
+					n = byte() & 3;
+					while (m--)
+						(void)byte();
+
+					/* actually read out the keystream into buf */
+					while (chunk--) {
+						*buf++ = byte();
+					}
+
+					/* dance around the bytes read from above, for protection */
+					while (n--)
+						(void)byte();
+				}
+			}
+
+		public:
+
+			Arc4random(void* bytes, size_t nbytes)
+			:
+				i(0),
+				j(0),
+				num(0),
+				initialised(0)
+			{
+				memset(S, 0, 256);
+			}
+
+			void get(void *_buf, size_t len)
+			{
+				buf(_buf, len);
+			}
+	};
+
+
+	class Random_file_system : public File_system
+	{
+		private:
+
+			Arc4random *_arc4random;
+
+			const char *_filename() { return "urandom"; }
+
+			bool _is_root(const char *path)
+			{
+				return (strcmp(path, "") == 0) || (strcmp(path, "/") == 0);
+			}
+
+			bool _is_device_random_file(const char *path)
+			{
+				return (strlen(path) == (strlen(_filename()) + 1)) &&
+					   (strcmp(&path[1], _filename()) == 0);
+			}
+
+		public:
+
+			Random_file_system(void *bytes, size_t nbytes)
+			{
+				_arc4random = new (env()->heap()) Arc4random(bytes, nbytes);
+			}
+
+			~Random_file_system()
+			{
+				destroy(env()->heap(), _arc4random);
+			}
+
+
+			/*********************************
+			 ** Directory-service interface **
+			 *********************************/
+
+			Dataspace_capability dataspace(char const *path)
+			{
+				/* not supported */
+				return Dataspace_capability();
+			}
+
+			void release(char const *path, Dataspace_capability ds_cap)
+			{
+				/* not supported */
+			}
+
+			bool stat(Sysio *sysio, char const *path)
+			{
+				Sysio::Stat st = { 0, 0, 0, 0, 0, 0 };
+
+				if (_is_root(path))
+					st.mode = Sysio::STAT_MODE_DIRECTORY;
+				else if (_is_device_random_file(path)) {
+					st.mode = Sysio::STAT_MODE_CHARDEV;
+				} else {
+					sysio->error.stat = Sysio::STAT_ERR_NO_ENTRY;
+					return false;
+				}
+
+				sysio->stat_out.st = st;
+				return true;
+			}
+
+			bool dirent(Sysio *sysio, char const *path, off_t index)
+			{
+				if (_is_root(path)) {
+					if (index == 0) {
+						sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_CHARDEV;
+						strncpy(sysio->dirent_out.entry.name,
+						        _filename(),
+						        sizeof(sysio->dirent_out.entry.name));
+					} else {
+						sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_END;
+					}
+
+					return true;
+				}
+
+				return false;
+			}
+
+			size_t num_dirent(char const *path)
+			{
+				if (_is_root(path))
+					return 1;
+				else
+					return 0;
+			}
+
+			bool is_directory(char const *path)
+			{
+				if (_is_root(path))
+					return true;
+
+				return false;
+			}
+
+			char const *leaf_path(char const *path)
+			{
+				return path;
+			}
+
+			Vfs_handle *open(Sysio *sysio, char const *path)
+			{
+				if (!_is_device_random_file(path)) {
+					sysio->error.open = Sysio::OPEN_ERR_UNACCESSIBLE;
+					return 0;
+				}
+
+				return new (env()->heap()) Vfs_handle(this, this, 0);
+			}
+
+			bool unlink(Sysio *sysio, char const *path)
+			{
+				/* not supported */
+				return false;
+			}
+
+			bool readlink(Sysio *sysio, char const *path)
+			{
+				/* not supported */
+				return false;
+			}
+
+			bool rename(Sysio *sysio, char const *from_path, char const *to_path)
+			{
+				/* not supported */
+				return false;
+			}
+
+			bool mkdir(Sysio *sysio, char const *path)
+			{
+				/* not supported */
+				return false;
+			}
+
+			bool symlink(Sysio *sysio, char const *path)
+			{
+				/* not supported */
+				return false;
+			}
+
+			/***************************
+			 ** File_system interface **
+			 ***************************/
+
+			char const *name() const { return "random"; }
+
+
+			/********************************
+			 ** File I/O service interface **
+			 ********************************/
+
+			bool write(Sysio *sysio, Vfs_handle *handle)
+			{
+				sysio->write_out.count = sysio->write_in.count;
+
+				return true;
+			}
+
+			bool read(Sysio *sysio, Vfs_handle *vfs_handle)
+			{
+				size_t nbytes = sysio->read_in.count;
+
+				_arc4random->get(sysio->read_out.chunk, nbytes);
+				sysio->read_out.count = nbytes;
+
+				return true;
+			}
+
+			bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) { return true; }
+	};
+}
+
+#endif /* _NOUX__RANDOM_H_ */