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:
committed by
Norman Feske
parent
1f028daae3
commit
33ebdeee1f
4
recipes/pkg/jitter_sponge/README
Normal file
4
recipes/pkg/jitter_sponge/README
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
Jitter Sponge
|
||||
|
||||
A terminal server that provides an entropy service.
|
||||
1
recipes/pkg/jitter_sponge/archives
Normal file
1
recipes/pkg/jitter_sponge/archives
Normal file
@@ -0,0 +1 @@
|
||||
_/src/jitter_sponge
|
||||
1
recipes/pkg/jitter_sponge/hash
Normal file
1
recipes/pkg/jitter_sponge/hash
Normal file
@@ -0,0 +1 @@
|
||||
-
|
||||
12
recipes/pkg/jitter_sponge/runtime
Normal file
12
recipes/pkg/jitter_sponge/runtime
Normal 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>
|
||||
23
recipes/src/jitter_sponge/content.mk
Normal file
23
recipes/src/jitter_sponge/content.mk
Normal 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)
|
||||
1
recipes/src/jitter_sponge/hash
Normal file
1
recipes/src/jitter_sponge/hash
Normal file
@@ -0,0 +1 @@
|
||||
-
|
||||
4
recipes/src/jitter_sponge/used_apis
Normal file
4
recipes/src/jitter_sponge/used_apis
Normal file
@@ -0,0 +1,4 @@
|
||||
base
|
||||
jitterentropy
|
||||
terminal_session
|
||||
vfs
|
||||
205
src/server/jitter_sponge/component.cc
Normal file
205
src/server/jitter_sponge/component.cc
Normal 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);
|
||||
}
|
||||
137
src/server/jitter_sponge/session_requests.h
Normal file
137
src/server/jitter_sponge/session_requests.h
Normal 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
|
||||
3
src/server/jitter_sponge/target.mk
Normal file
3
src/server/jitter_sponge/target.mk
Normal file
@@ -0,0 +1,3 @@
|
||||
TARGET = jitter_sponge
|
||||
LIBS += libkeccak jitterentropy base
|
||||
SRC_CC += component.cc
|
||||
Reference in New Issue
Block a user