mirror of
https://github.com/genodelabs/genode.git
synced 2025-03-25 05:25:32 +00:00
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!
This commit is contained in:
parent
7f359a5978
commit
c24a95b819
@ -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));
|
||||
|
407
ports/src/noux/random_file_system.h
Normal file
407
ports/src/noux/random_file_system.h
Normal file
@ -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_ */
|
Loading…
x
Reference in New Issue
Block a user