diff options
-rw-r--r-- | README | 21 | ||||
-rw-r--r-- | ebin/plop.app | 2 | ||||
-rw-r--r-- | include/plop.hrl | 34 | ||||
-rw-r--r-- | src/db.erl | 16 | ||||
-rw-r--r-- | src/db.hrl | 8 | ||||
-rw-r--r-- | src/plop.erl | 49 | ||||
l--------- | src/plop.hrl | 1 | ||||
-rw-r--r-- | src/plop_app.erl | 6 | ||||
-rw-r--r-- | src/plop_sup.erl | 2 | ||||
-rw-r--r-- | test/plop_test.erl (renamed from src/test/plop_test.erl) | 2 | ||||
-rw-r--r-- | test/rsakey.pem (renamed from src/test/rsakey.pem) | 0 |
11 files changed, 81 insertions, 60 deletions
@@ -12,8 +12,27 @@ Compile the application Start the application locally - $ erl -boot start_sasl -pa ebin -eval "application:start(plop)." -plop Keyfile "src/test/rsakey.pem" -plop Passphrase "sikrit" + Very first time, before there is a database: + $ erl -boot start_sasl -pa ebin -eval "plop_app:install([node()])." + There should now exist a directory Mnesia.nonode@nohost/ with four + files in it. + + Start the application: + $ erl -boot start_sasl -pa ebin \ + -eval "application:start(mnesia), application:start(plop)." + + FIXME: mnesia isn't starting automagically, why? + TODO: -plop Keyfile "test/rsakey.pem" -plop Passphrase "sikrit" Test the application [FIXME] + +Moving the database files + + Add `-mnesia dir "/some/path"' to the list of arguments to erl. + +Debugging + + Dump the database to a file: + 1> db:dump_to_file("dump.txt"). diff --git a/ebin/plop.app b/ebin/plop.app index f8d5d2c..55d5648 100644 --- a/ebin/plop.app +++ b/ebin/plop.app @@ -3,7 +3,7 @@ [{description, "The plop store"}, {vsn, "0.0.1"}, {modules, [plop_app, plop_sup, plop, db, ht, hex]}, - {applications, [kernel, stdlib]}, % crypto, public_key, mnesia + {applications, [kernel, stdlib, mnesia]}, % crypto, public_key, mnesia {registered, [plop, db]}, {mod, {plop_app, []}} % <-- key file and pass phrase ]}. diff --git a/include/plop.hrl b/include/plop.hrl index 5492024..30a5385 100644 --- a/include/plop.hrl +++ b/include/plop.hrl @@ -6,14 +6,9 @@ -type entry_type() :: x509 | precert | test. % uint16 -type leaf_type() :: timestamped_entry | test. % uint8 -%% @doc What's stored in the database. --record(plop, { - index :: non_neg_integer(), % Primary key. - hash :: binary(), % SHA-256 over #FIXME.entry. Indexed in db. - spt :: binary() % serialise(#spt_on_wire{}) - }). - -%% @doc Merkle Tree Leaf -- input to hash function for leaf hashes. +%% @doc Merkle Tree Leaf -- what's sent as 'leaf_input' in response to +%% get-entries requests and also the input to the hash function for +%% leaf hashes in the tree. RFC 6962 sect 3.4. -record(mtl, { version = 1 :: pos_integer(), leaf_type = timestamped_entry :: leaf_type(), @@ -21,14 +16,6 @@ }). -type mtl() :: #mtl{}. -%% @doc Parts of what goes in an SPT. Used for FIXME. -%% -record(spt, { -%% version = 1 :: pos_integer(), -%% signature_type :: signature_type(), -%% entry :: timestamped_entry() -%% }). -%%-type spt() :: #spt{}. - -record(spt_on_wire, { version :: pos_integer(), % uint8 logid :: binary(), % SHA-256 over DER encoded public log key @@ -48,14 +35,6 @@ }). -type spt_signed() :: #spt_signed{}. -%% Internal representation of a data entry. --record(timestamped_entry, { - timestamp = now :: now | integer(), - entry_type :: entry_type(), - entry :: binary() - }). --type timestamped_entry() :: #timestamped_entry{}. - %% %% Part of interface to plop:add/1. %% -record(plop_entry, { %% type :: entry_type(), @@ -63,6 +42,13 @@ %% }). %% -type plop_entry() :: #plop_entry{}. +%% A data entry. +-record(timestamped_entry, { + timestamp = now :: now | integer(), + entry_type :: entry_type(), + entry :: binary() + }). +-type timestamped_entry() :: #timestamped_entry{}. %% @doc The parts of an STH which is to be signed. Used as the %% interface to plop:sth/1, for testing. Should probably be internal @@ -12,27 +12,30 @@ code_change/3]). -include_lib("stdlib/include/qlc.hrl"). +-include("db.hrl"). -include("plop.hrl"). %% @doc Set up a database schema on all nodes that are to be included %% in the "database cluster". Has to be run _before_ mnesia has been %% started. init_db() -> - init_db([]). + init_db([node()]). init_db(Nodes) -> - mnesia:create_schema([node()] ++ Nodes), - init_tables(Nodes). + ok = mnesia:create_schema(Nodes), + rpc:multicall(Nodes, application, start, [mnesia]), + init_tables(Nodes), + rpc:multicall(Nodes, application, stop, [mnesia]). %% @doc Run once, or rather every time you start on a new database. %% If run more than once, we'll get {aborted, {already_exists, TABLE}}. init_tables() -> - init_tables([]). + init_tables([node()]). init_tables(Nodes) -> %% We've once upon a time invoked mnesia:create_schema/1 with the %% nodes that will be part of the database. RamCopies = [], DiscCopies = [], - DiscOnlyCopies = [node()] ++ Nodes, + DiscOnlyCopies = Nodes, mnesia:start(), mnesia:create_table(plop, [{type, set}, {ram_copies, RamCopies}, @@ -48,7 +51,8 @@ dump_to_file(Filename) -> mnesia:dump_to_textfile(Filename). init(_Args) -> - {ok, []}. % TODO: return state + {mnesia:wait_for_tables([plop], 5000), + []}. start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). diff --git a/src/db.hrl b/src/db.hrl new file mode 100644 index 0000000..16b9103 --- /dev/null +++ b/src/db.hrl @@ -0,0 +1,8 @@ +%% @doc What's stored in the database. +%% 'index' is the primary key, 'hash' is also indexed. +-record(plop, { + index :: non_neg_integer(), % Primary key. + hash :: binary(), % Hash over mtl. + mtl :: mtl(), % Merkle Tree Leaf, an #mtl{}. + spt_text :: binary() % Signed Plop Timestamp, an #spt_on_wire{}. + }). diff --git a/src/plop.erl b/src/plop.erl index a55e4ca..63545f0 100644 --- a/src/plop.erl +++ b/src/plop.erl @@ -21,6 +21,7 @@ handle_cast/2, handle_info/2, code_change/3]). -include("plop.hrl"). +-include("db.hrl"). -include_lib("public_key/include/public_key.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -95,29 +96,27 @@ handle_call({sth, Data}, _From, %%%%%%%%%%%%%%%%%%%% +-spec do_add(timestamped_entry(), public_key:rsa_private_key(), binary(), any()) -> {any(), binary()}. do_add(TimestampedEntry, Privkey, LogID, Tree) -> - H = crypto:hash(sha256, serialise(TimestampedEntry)), - Record = db:find(H), - TmpFixm = case Record of - #plop{index = I, spt = S} -> - io:format("Found entry w/ index=~p, SPT: ~p~n", [I, S]), - %% DB consistency check: - %%Record = #plop{hash = H, spt = serialise(Data)}, % FIXME: Remove. - {Tree, % State not changed. - S}; % Cached SPT. - _ -> - NewSPT = spt(LogID, Privkey, TimestampedEntry), - DbData = #plop{index = ht:size(Tree) + 1, - hash = H, - spt = NewSPT}, - db:add(DbData), - LeafData = #mtl{version = 1, - leaf_type = timestamped_entry, - entry = TimestampedEntry}, - {ht:append(Tree, serialise(LeafData)), % New tree. - NewSPT} % New SPT. - end, - TmpFixm. + MTL = #mtl{entry = TimestampedEntry}, + MTL_text = serialise(MTL), + DB_hash = crypto:hash(sha256, MTL_text), + case db:find(DB_hash) of + #plop{index = I, mtl = M, spt_text = SPT} -> + io:format("Found entry: index=~p, MTL: ~p, SPT: ~p~n", [I, M, SPT]), + %% DB consistency check: + %%Record = #plop{hash = H, spt = serialise(Data)}, % FIXME: Remove. + {Tree, SPT}; % State not changed, cached SPT. + _ -> + NewSPT = spt(LogID, Privkey, TimestampedEntry), + DB_data = #plop{index = ht:size(Tree) + 1, + hash = DB_hash, + mtl = MTL, + spt_text = NewSPT}, + db:add(DB_data), + {ht:append(Tree, MTL_text), % New tree. + NewSPT} % New SPT. + end. %% @doc Signed Plop Timestamp, conformant to an SCT in RFC6962 3.2 and %% RFC5246 4.7. @@ -288,12 +287,12 @@ serialise_test_() -> signed_entry = <<"foo">>})))]. add_test_() -> {ok, S} = init([?TESTKEYFILE, ?TESTKEYPASSPHRASE]), - [?_assertEqual( - <<"fixme">>, + {_Tree, SPT} = do_add(#timestamped_entry{ timestamp = 4711, entry_type = test, entry = <<"some data">>}, S#state.privkey, S#state.logid, - S#state.hashtree))]. + S#state.hashtree), + [?_assertEqual(<<"fixme:SPT">>, SPT)]. diff --git a/src/plop.hrl b/src/plop.hrl new file mode 120000 index 0000000..38dfcbf --- /dev/null +++ b/src/plop.hrl @@ -0,0 +1 @@ +/home/linus/usr/src/plop/include/plop.hrl
\ No newline at end of file diff --git a/src/plop_app.erl b/src/plop_app.erl index d2e99ac..0a972cc 100644 --- a/src/plop_app.erl +++ b/src/plop_app.erl @@ -1,8 +1,12 @@ -module(plop_app). -behaviour(application). -export([start/2, stop/1]). +-export([install/1]). -start(_Type, Args) -> +install(Nodes) -> + db:init_db(Nodes). + +start(normal, Args) -> plop_sup:start_link(Args). stop(_State) -> diff --git a/src/plop_sup.erl b/src/plop_sup.erl index 18ed926..3d0e66d 100644 --- a/src/plop_sup.erl +++ b/src/plop_sup.erl @@ -18,7 +18,7 @@ init(_Args) -> [{the_plop, {plop, start_link, []}, % Here's where key file name and pass phrase go. permanent, - 10000, % Shut down in 10s. + 10000, % Shut down within 10s. worker, [plop]}, {the_db, {db, start_link, []}, diff --git a/src/test/plop_test.erl b/test/plop_test.erl index 8a308c0..79dbbd3 100644 --- a/src/test/plop_test.erl +++ b/test/plop_test.erl @@ -19,7 +19,7 @@ adding_verifying_test() -> %%% Setup. start() -> - {ok, Pid} = plop:start_link("test/rsakey.pem", "sikrit"), + {ok, Pid} = plop:start_link("../test/rsakey.pem", "sikrit"), Pid. stop(_) -> diff --git a/src/test/rsakey.pem b/test/rsakey.pem index 8e3fc97..8e3fc97 100644 --- a/src/test/rsakey.pem +++ b/test/rsakey.pem |