Jitter sponge entropy server

A terminal server that reads out entropy generated from CPU jitter
amplified using a Keccak sponge construction.
This commit is contained in:
Emery Hemingway
2018-11-10 15:08:51 +01:00
committed by Norman Feske
parent 1f028daae3
commit 33ebdeee1f
10 changed files with 391 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
Jitter Sponge
A terminal server that provides an entropy service.

View File

@@ -0,0 +1 @@
_/src/jitter_sponge

View File

@@ -0,0 +1 @@
-

View File

@@ -0,0 +1,12 @@
<runtime ram="4M" caps="128" binary="jitter_sponge">
<provides> <terminal/> </provides>
<content>
<rom label="ld.lib.so"/>
<rom label="jitter_sponge"/>
</content>
<config/>
</runtime>

View File

@@ -0,0 +1,23 @@
SRC_DIR = src/server/jitter_sponge
include $(GENODE_DIR)/repos/base/recipes/src/content.inc
MIRROR_FROM_REP_DIR = \
lib/import/import-libkeccak.mk \
lib/mk/libkeccak.inc \
lib/mk/spec/32bit/libkeccak.mk \
lib/mk/spec/64bit/libkeccak.mk \
src/lib/keccak \
$(MIRROR_FROM_REP_DIR):
$(mirror_from_rep_dir)
XKCP_PORT_DIR := $(call port_dir,$(REP_DIR)/ports/xkcp)
MIRROR_FROM_XKCP = generic32 generic64
generic32: $(XKCP_PORT_DIR)/generic32
cp -r $< $@
generic64: $(XKCP_PORT_DIR)/generic64
cp -r $< $@
content: $(MIRROR_FROM_REP_DIR) $(MIRROR_FROM_XKCP)

View File

@@ -0,0 +1 @@
-

View File

@@ -0,0 +1,4 @@
base
jitterentropy
terminal_session
vfs

View File

@@ -0,0 +1,205 @@
/*
* \brief Jitter/Keccak entropy server
* \author Emery Hemingway
* \date 2018-11-06
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* local includes */
#include "session_requests.h"
#include <terminal_session/connection.h>
#include <base/attached_ram_dataspace.h>
#include <base/heap.h>
#include <base/component.h>
/* Jitterentropy includes */
#include <jitterentropy.h>
/* Keccak includes */
extern "C" {
#include <KeccakPRGWidth1600.h>
}
namespace Jitter_sponge {
using namespace Genode;
struct Generator;
class Session_component;
struct Main;
typedef Genode::Id_space<Session_component> Session_space;
struct Collection_failure : Genode::Exception { };
}
struct Jitter_sponge::Generator
{
KeccakWidth1600_SpongePRG_Instance sponge { };
struct rand_data *jitter = nullptr;
void die(char const *msg)
{
/* forget sponge state */
KeccakWidth1600_SpongePRG_Forget(&sponge);
Genode::error(msg);
throw Exception();
}
Generator(Allocator &alloc)
{
jitterentropy_init(alloc);
if (jent_entropy_init())
die("jitterentropy library could not be initialized!");
jitter = jent_entropy_collector_alloc(0, 0);
if (!jitter)
die("failed to allocate jitter entropy collector");
if (KeccakWidth1600_SpongePRG_Initialize(&sponge, 254))
die("failed to initialize sponge");
}
void mix()
{
/* mix at entry and exit of 'read', so 32 bytes are mixed between reads */
enum { MIX_BYTES = 16};
char buf[MIX_BYTES];
if (jent_read_entropy(jitter, buf, MIX_BYTES) != MIX_BYTES)
die("jitter collection failed");
if (KeccakWidth1600_SpongePRG_Feed(&sponge, (unsigned char *)buf, MIX_BYTES))
die("failed to feed sponge");
}
void fetch(unsigned char *buf, size_t n)
{
if (KeccakWidth1600_SpongePRG_Fetch(&sponge, buf, n))
die("failed to fetch from sponge");
}
};
class Jitter_sponge::Session_component final : public Genode::Rpc_object<Terminal::Session, Session_component>
{
private:
Session_component(Session_component const &);
Session_component &operator = (Session_component const &);
Session_space::Element _sessions_elem;
Genode::Attached_ram_dataspace _io_buffer;
Generator &_generator;
public:
Session_component(Genode::Env &env,
Session_space &space,
Session_space::Id id,
Generator &generator)
:
_sessions_elem(*this, space, id),
_io_buffer(env.pd(), env.rm(), 0x1000),
_generator(generator)
{ }
Genode::Dataspace_capability _dataspace() {
return _io_buffer.cap(); }
Genode::size_t _read(Genode::size_t n)
{
_generator.mix();
n = min(n, _io_buffer.size());
_generator.fetch(_io_buffer.local_addr<unsigned char>(), n);
_generator.mix();
return n;
}
Genode::size_t read(void *, Genode::size_t) { return 0; }
Genode::size_t _write(Genode::size_t) { return 0; }
Genode::size_t write(void const *, Genode::size_t) { return 0; }
Size size() { return Size(0, 0); }
bool avail() { return false; }
void connected_sigh(Genode::Signal_context_capability cap) {
Genode::Signal_transmitter(cap).submit(); }
void read_avail_sigh(Genode::Signal_context_capability) { }
void size_changed_sigh(Genode::Signal_context_capability) { }
};
struct Jitter_sponge::Main : Session_request_handler
{
Genode::Env &_env;
Heap _entropy_heap { _env.pd(), _env.rm() };
Sliced_heap _session_heap { _env.pd(), _env.rm() };
Generator _generator { _entropy_heap };
Session_space _sessions { };
void handle_session_create(Session_state::Name const &,
Parent::Server::Id pid,
Session_state::Args const &args) override
{
size_t ram_quota =
Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0);
size_t session_size =
max((size_t)4096, sizeof(Session_component));
if (ram_quota < session_size)
throw Insufficient_ram_quota();
Session_space::Id id { pid.value };
Session_component *session = new (_session_heap)
Session_component(_env, _sessions, id, _generator);
_env.parent().deliver_session_cap(pid, _env.ep().manage(*session));
_generator.mix();
}
void handle_session_upgrade(Parent::Server::Id,
Session_state::Args const &) override { }
void handle_session_close(Parent::Server::Id pid) override
{
Session_space::Id id { pid.value };
_sessions.apply<Session_component&>(
id, [&] (Session_component &session)
{
_env.ep().dissolve(session);
destroy(_session_heap, &session);
_env.parent().session_response(pid, Parent::SESSION_CLOSED);
});
}
Session_requests_rom _session_requests { _env, *this };
Main(Genode::Env &env) : _env(env)
{
env.parent().announce("Terminal");
/* process any requests that have already queued */
_session_requests.schedule();
}
};
void Component::construct(Genode::Env &env)
{
static Jitter_sponge::Main inst(env);
}

View File

@@ -0,0 +1,137 @@
/*
* \brief Utilities for handling the 'session_requests' ROM
* \author Emery Hemingway
* \date 2018-04-08
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef __SESSION_REQUESTS_H_
#define __SESSION_REQUESTS_H_
#include <base/attached_rom_dataspace.h>
#include <base/session_state.h>
#include <base/component.h>
namespace Genode {
struct Session_request_handler;
class Session_requests_rom;
};
struct Genode::Session_request_handler : Interface
{
virtual void handle_session_create(Session_state::Name const &,
Parent::Server::Id,
Session_state::Args const &) = 0;
virtual void handle_session_upgrade(Parent::Server::Id,
Session_state::Args const &) { }
virtual void handle_session_close(Parent::Server::Id) = 0;
};
class Genode::Session_requests_rom : public Signal_handler<Session_requests_rom>
{
private:
Parent &_parent;
Session_request_handler &_requests_handler;
Attached_rom_dataspace _parent_rom;
void _process()
{
_parent_rom.update();
Xml_node requests = _parent_rom.xml();
auto const create_fn = [&] (Xml_node request)
{
Parent::Server::Id const id {
request.attribute_value("id", ~0UL) };
typedef Session_state::Name Name;
typedef Session_state::Args Args;
Name name { };
Args args { };
try {
name = request.attribute_value("service", Name());
args = request.sub_node("args").decoded_content<Args>();
} catch (...) {
Genode::error("failed to parse request ", request);
return;
}
try { _requests_handler.handle_session_create(name, id, args); }
catch (Service_denied) {
_parent.session_response(id, Parent::SERVICE_DENIED); }
catch (Insufficient_ram_quota) {
_parent.session_response(id, Parent::INSUFFICIENT_RAM_QUOTA); }
catch (Insufficient_cap_quota) {
_parent.session_response(id, Parent::INSUFFICIENT_CAP_QUOTA); }
catch (...) {
error("unhandled exception while creating session");
_parent.session_response(id, Parent::SERVICE_DENIED);
throw;
}
};
auto const upgrade_fn = [&] (Xml_node request)
{
Parent::Server::Id const id {
request.attribute_value("id", ~0UL) };
typedef Session_state::Args Args;
Args args { };
try { args = request.sub_node("args").decoded_content<Args>(); }
catch (...) {
Genode::error("failed to parse request ", request);
return;
}
_requests_handler.handle_session_upgrade(id, args);
};
auto const close_fn = [&] (Xml_node request)
{
Parent::Server::Id const id {
request.attribute_value("id", ~0UL) };
_requests_handler.handle_session_close(id);
};
/* close sessions to free resources */
requests.for_each_sub_node("close", close_fn);
/* service existing sessions */
requests.for_each_sub_node("upgrade", upgrade_fn);
/* create new sessions */
requests.for_each_sub_node("create", create_fn);
}
public:
Session_requests_rom(Genode::Env &env,
Session_request_handler &requests_handler)
: Signal_handler<Session_requests_rom>(env.ep(), *this, &Session_requests_rom::_process),
_parent(env.parent()),
_requests_handler(requests_handler),
_parent_rom(env, "session_requests")
{
_parent_rom.sigh(*this);
}
/**
* Post a signal to this requests handler
*/
void schedule() {
Signal_transmitter(*this).submit(); }
};
#endif

View File

@@ -0,0 +1,3 @@
TARGET = jitter_sponge
LIBS += libkeccak jitterentropy base
SRC_CC += component.cc