summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Nordberg <linus@nordu.net>2014-05-02 18:21:47 +0200
committerLinus Nordberg <linus@nordu.net>2014-05-02 18:21:47 +0200
commitdf6fca69a7d9bb11d7c6116a9cc4062a6e5e040d (patch)
treeddb03b65a863384057696300bc756bd863621f59
parentd1adbd1523f6d584fd9d060e4224ca07251aeb46 (diff)
Sign using ECDSA and fix a couple bugs.
Revive the plop_entry and hash over that instead of the full MTL, for the db hash. We don't want the timestamp in that hash! Use ECDSA instead of RSA for signing stuff. That's what Google does and we want to use their test suites. An annoyance with DSA is that the signature isn't deterministic. Testing just became less easy. Fix db:find() now that the hash is no longer the primary key.
-rw-r--r--ebin/plop.app2
-rw-r--r--include/plop.hrl21
-rw-r--r--src/db.erl15
-rw-r--r--src/db.hrl4
-rw-r--r--src/plop.erl176
-rw-r--r--test/eckey-public.pem4
-rw-r--r--test/eckey.pem8
-rw-r--r--test/plop_test.erl108
8 files changed, 204 insertions, 134 deletions
diff --git a/ebin/plop.app b/ebin/plop.app
index 55d5648..dd40311 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, mnesia]}, % crypto, public_key, mnesia
+ {applications, [kernel, stdlib, mnesia]}, % crypto, public_key
{registered, [plop, db]},
{mod, {plop_app, []}} % <-- key file and pass phrase
]}.
diff --git a/include/plop.hrl b/include/plop.hrl
index 30a5385..8115374 100644
--- a/include/plop.hrl
+++ b/include/plop.hrl
@@ -35,21 +35,22 @@
}).
-type spt_signed() :: #spt_signed{}.
-%% %% Part of interface to plop:add/1.
-%% -record(plop_entry, {
-%% type :: entry_type(),
-%% data :: binary()
-%% }).
-%% -type plop_entry() :: #plop_entry{}.
-
-%% A data entry.
+%% A plop entry with timestamp. Part of the Merkle Tree Leaf
+%% structure.
-record(timestamped_entry, {
timestamp = now :: now | integer(),
- entry_type :: entry_type(),
- entry :: binary()
+ entry :: plop_entry()
}).
-type timestamped_entry() :: #timestamped_entry{}.
+%% An entry, without the timestamp. This is what we hash over and
+%% store in the the database for finding duplicated submissions.
+-record(plop_entry, {
+ type :: entry_type(),
+ data :: binary()
+ }).
+-type plop_entry() :: #plop_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
%% to plop, if that can be arranged wrt testing.
diff --git a/src/db.erl b/src/db.erl
index 857615c..3529080 100644
--- a/src/db.erl
+++ b/src/db.erl
@@ -51,8 +51,7 @@ dump_to_file(Filename) ->
mnesia:dump_to_textfile(Filename).
init(_Args) ->
- {mnesia:wait_for_tables([plop], 5000),
- []}.
+ {mnesia:wait_for_tables([plop], 5000), []}.
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
@@ -100,4 +99,14 @@ handle_call({dump, Table}, _From, State) ->
Res = mnesia:transaction(F),
{reply, Res, State};
handle_call({find, Hash}, _From, State) ->
- {reply, mnesia:dirty_read({plop, Hash}), State}.
+ F = fun() ->
+ mnesia:select(plop,
+ [{#plop{hash = Hash, _='_'}, [], ['$_']}])
+ end,
+ {atomic, Result} = mnesia:transaction(F),
+ Record = case length(Result) of
+ 0 -> [];
+ 1 -> hd(Result);
+ _ -> duplicate_hash_in_db % FIXME: log an error
+ end,
+ {reply, Record, State}.
diff --git a/src/db.hrl b/src/db.hrl
index 16b9103..ce6df7b 100644
--- a/src/db.hrl
+++ b/src/db.hrl
@@ -2,7 +2,7 @@
%% '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{}.
+ hash :: binary(), % Hash over #plop_entry{} in 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 63545f0..5ca595f 100644
--- a/src/plop.erl
+++ b/src/plop.erl
@@ -16,6 +16,8 @@
-export([add/1, sth/0]).
%% API for tests.
-export([sth/1]).
+-export([read_keyfile_rsa/2, read_keyfiles_ec/2]).
+-export([testing_get_pubkey/0]).
%% gen_server callbacks.
-export([init/1, handle_call/3, terminate/2,
handle_cast/2, handle_info/2, code_change/3]).
@@ -26,8 +28,8 @@
-include_lib("eunit/include/eunit.hrl").
-define(PLOPVERSION, 1).
--define(TESTKEYFILE, "src/test/rsakey.pem").
--define(TESTKEYPASSPHRASE, "sikrit").
+-define(TESTPRIVKEYFILE, "test/eckey.pem").
+-define(TESTPUBKEYFILE, "test/eckey-public.pem").
-record(state, {pubkey :: public_key:rsa_public_key(),
privkey :: public_key:rsa_private_key(),
@@ -35,7 +37,7 @@
hashtree :: ht:head()}).
start_link() ->
- start_link(?TESTKEYFILE, ?TESTKEYPASSPHRASE). % FIXME: Remove.
+ start_link(?TESTPRIVKEYFILE, ?TESTPUBKEYFILE). % FIXME: Remove.
start_link(Keyfile, Passphrase) ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [Keyfile, Passphrase], []).
@@ -43,10 +45,16 @@ stop() ->
gen_server:call(?MODULE, stop).
%%%%%%%%%%%%%%%%%%%%
-init([Keyfile, Passphrase]) ->
- {Private_key, Public_key} = read_keyfile(Keyfile, Passphrase),
- LogID = crypto:hash(sha256,
- public_key:der_encode('RSAPublicKey', Public_key)),
+init([PubKeyfile, PrivKeyfile]) ->
+ %% Read RSA keypair.
+ %% {Private_key, Public_key} = read_keyfile_rsa(Keyfile, Passphrase),
+ %% LogID = crypto:hash(sha256,
+ %% public_key:der_encode('RSAPublicKey', Public_key)),
+ %% Read EC keypair.
+ {Private_key, Public_key} = read_keyfiles_ec(PubKeyfile, PrivKeyfile),
+ LogID = crypto:hash(sha256, public_key:der_encode(
+ 'ECPoint',
+ element(2, element(1, Public_key)))), % FIXME!
{ok, #state{pubkey = Public_key,
privkey = Private_key,
logid = LogID,
@@ -74,6 +82,8 @@ sth() ->
sth(Data) ->
gen_server:call(?MODULE, {sth, Data}).
+testing_get_pubkey() ->
+ gen_server:call(?MODULE, {test, pubkey}).
%%%%%%%%%%%%%%%%%%%%
handle_call(stop, _From, State) ->
{stop, normal, stopped, State};
@@ -86,35 +96,46 @@ handle_call({add, #timestamped_entry{} = TimestampedEntry},
logid = LogID,
hashtree = Tree}) ->
{NewTree, SPT} = do_add(TimestampedEntry, Privkey, LogID, Tree),
- io:format("Index: ~p~nSPT: ~p~n", [ht:size(NewTree), SPT]),
{reply, SPT, State#state{hashtree = NewTree}};
handle_call({sth, Data}, _From,
Plop = #state{privkey = PrivKey,
hashtree = Tree}) ->
- {reply, sth(PrivKey, Tree, Data), Plop}.
+ {reply, sth(PrivKey, Tree, Data), Plop};
+
+handle_call({test, pubkey}, _From,
+ Plop = #state{pubkey = PK}) ->
+ {reply, PK, Plop}.
%%%%%%%%%%%%%%%%%%%%
-spec do_add(timestamped_entry(), public_key:rsa_private_key(), binary(), any()) -> {any(), binary()}.
-do_add(TimestampedEntry, Privkey, LogID, Tree) ->
- 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.
+do_add(TimestampedEntry = #timestamped_entry{entry = PlopEntry},
+ Privkey, LogID, Tree) ->
+ DB_hash = crypto:hash(sha256, serialise(PlopEntry)),
+ Record = db:find(DB_hash),
+ case Record of
+ #plop{index = I, mtl = M = #mtl{entry = E}, spt_text = SPT} ->
+ io:format("Found entry: index=~p~nMTL: ~p~nSPT: ~p~n", [I, M, SPT]),
+ Record = Record#plop{ % DB consistency checking.
+ hash = DB_hash,
+ mtl = #mtl{entry =
+ #timestamped_entry{
+ timestamp = E#timestamped_entry.timestamp,
+ entry = PlopEntry}
+ }},
{Tree, SPT}; % State not changed, cached SPT.
_ ->
NewSPT = spt(LogID, Privkey, TimestampedEntry),
+ MTL = #mtl{entry = TimestampedEntry},
+ io:format("Creating new entry: index=~p~ndb hash: ~p~nMTL: ~p~nSPT: ~p~n",
+ [ht:size(Tree) + 1, DB_hash, MTL, NewSPT]),
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.
+ {ht:append(Tree, serialise(MTL)), % New tree.
NewSPT} % New SPT.
end.
@@ -123,8 +144,7 @@ do_add(TimestampedEntry, Privkey, LogID, Tree) ->
-spec spt(binary(), public_key:rsa_private_key(), timestamped_entry()) -> binary().
spt(LogID, PrivKey, #timestamped_entry{
timestamp = Timestamp_in,
- entry_type = EntryType,
- entry = Entry
+ entry = #plop_entry{type = EntryType, data = EntryData}
}) ->
Timestamp = timestamp(Timestamp_in),
BinToSign =
@@ -133,18 +153,16 @@ spt(LogID, PrivKey, #timestamped_entry{
signature_type = certificate_timestamp,
timestamp = Timestamp,
entry_type = EntryType,
- signed_entry = Entry})),
+ signed_entry = EntryData})),
Signature = signhash(BinToSign, PrivKey),
SPT = serialise(#spt_on_wire{
version = ?PLOPVERSION,
logid = LogID,
timestamp = Timestamp,
signature = Signature}),
- io:format("SPT: ~p~nBinToSign: ~p~nSignature = ~p~n",
- [SPT, BinToSign, Signature]),
list_to_binary(SPT).
-%% @doc Signed Tree Head as described in RFC6962 section 3.2.
+%% @doc Signed Tree Head as specified in RFC6962 section 3.2.
sth(PrivKey, Tree, []) ->
sth(PrivKey, Tree, #sth{timestamp = now});
sth(PrivKey, Tree, #sth{version = Version, timestamp = Timestamp_in}) ->
@@ -166,24 +184,64 @@ sth(PrivKey, Tree, #sth{version = Version, timestamp = Timestamp_in}) ->
[STH, BinToSign, Signature, Timestamp]),
STH.
-read_keyfile(Filename, Passphrase) ->
+%% TODO: Merge the keyfile reading functions.
+
+%% Read one password protected PEM file with an RSA keypair.
+read_keyfile_rsa(Filename, Passphrase) ->
{ok, PemBin} = file:read_file(Filename),
- [Entry] = public_key:pem_decode(PemBin),
- Privatekey = public_key:pem_entry_decode(Entry, Passphrase),
+ [KeyPem] = public_key:pem_decode(PemBin), % Use first entry.
+ Privatekey = decode_key(KeyPem, Passphrase),
{Privatekey, public_key(Privatekey)}.
+%% Read two PEM files, one with a private EC key and one with the
+%% corresponding public EC key.
+read_keyfiles_ec(PrivkeyFile, Pubkeyfile) ->
+ {ok, PemBinPriv} = file:read_file(PrivkeyFile),
+ [OTPPubParamsPem, PrivkeyPem] = public_key:pem_decode(PemBinPriv),
+ Privatekey = decode_key(PrivkeyPem),
+
+ {_, ParamsBin, ParamsEnc} = OTPPubParamsPem,
+ PubParamsPem = {'EcpkParameters', ParamsBin, ParamsEnc},
+ Params = public_key:pem_entry_decode(PubParamsPem),
+
+ {ok, PemBinPub} = file:read_file(Pubkeyfile),
+ [SPKIPem] = public_key:pem_decode(PemBinPub),
+ %% SPKI is missing #'AlgorithmIdentifier' so pem_entry_decode won't do.
+ %% Publickey = public_key:pem_entry_decode(SPKIPem),
+ #'SubjectPublicKeyInfo'{algorithm = AlgoDer} = SPKIPem,
+ SPKI = public_key:der_decode('SubjectPublicKeyInfo', AlgoDer),
+ #'SubjectPublicKeyInfo'{subjectPublicKey = {_, Octets}} = SPKI,
+ Point = #'ECPoint'{point = Octets},
+ Publickey = {Point, Params},
+
+ {Privatekey, Publickey}.
+
+decode_key(Entry) ->
+ public_key:pem_entry_decode(Entry).
+decode_key(Entry, Passphrase) ->
+ public_key:pem_entry_decode(Entry, Passphrase).
+
public_key(#'RSAPrivateKey'{modulus = Mod, publicExponent = Exp}) ->
#'RSAPublicKey'{modulus = Mod, publicExponent = Exp}.
--spec signhash(iolist() | binary(), public_key:rsa_private_key()) -> binary().
-signhash(Data, PrivKey) ->
- %% Was going to just crypto:sign/3 the hash but looking at
- %% digitally_signed() in lib/ssl/src/ssl_handshake.erl it seems
- %% like we should rather use (undocumented) encrypt_private/3.
- %public_key:sign(hash(sha256, BinToSign), sha256, PrivKey)
- public_key:encrypt_private(crypto:hash(sha256, Data),
- PrivKey,
- [{rsa_pad, rsa_pkcs1_padding}]).
+
+%% FIXME: Merge RSA and DC.
+signhash(D, K) ->
+ signhash_ec(D, K).
+
+-spec signhash_ec(iolist() | binary(), public_key:ec_private_key()) -> binary().
+signhash_ec(Data, PrivKey) ->
+ public_key:sign(Data, sha256, PrivKey).
+
+%% -spec signhash_rsa(iolist() | binary(), public_key:rsa_private_key()) -> binary().
+%% signhash_rsa(Data, PrivKey) ->
+%% %% Was going to just crypto:sign/3 the hash but looking at
+%% %% digitally_signed() in lib/ssl/src/ssl_handshake.erl it seems
+%% %% like we should rather use (undocumented) encrypt_private/3.
+%% %public_key:sign(hash(sha256, BinToSign), sha256, PrivKey)
+%% public_key:encrypt_private(crypto:hash(sha256, Data),
+%% PrivKey,
+%% [{rsa_pad, rsa_pkcs1_padding}]).
%%%%%%%%%%%%%%%%%%%%
%% Serialisation of data.
@@ -216,16 +274,20 @@ timestamp(Timestamp) ->
_ -> Timestamp
end.
--spec serialise(timestamped_entry() | spt_on_wire() | spt_signed() | mtl() | sth()) -> iolist().
+-spec serialise(plop_entry() | timestamped_entry() | spt_on_wire() | spt_signed() | mtl() | sth()) -> iolist().
+serialise(#plop_entry{
+ type = TypeAtom,
+ data = Data
+ }) ->
+ EntryType = entry_type(TypeAtom),
+ [<<EntryType:16,
+ Data/binary>>];
serialise(#timestamped_entry{
timestamp = Timestamp,
- entry_type = TypeAtom,
- entry = Entry
+ entry = PlopEntry
}) ->
- EntryType = entry_type(TypeAtom),
- [<<Timestamp:64,
- EntryType:16,
- Entry/binary>>];
+ [<<Timestamp:64>>,
+ serialise(PlopEntry)];
serialise(#spt_on_wire{
version = Version,
logid = LogID,
@@ -285,14 +347,30 @@ serialise_test_() ->
timestamp = 0,
entry_type = x509,
signed_entry = <<"foo">>})))].
-add_test_() ->
- {ok, S} = init([?TESTKEYFILE, ?TESTKEYPASSPHRASE]),
+%%add_test_() ->
+add_test() ->
+ {ok, S} = init([?TESTPRIVKEYFILE, ?TESTPUBKEYFILE]),
+
+ Data1 = <<"some data">>,
{_Tree, SPT} =
do_add(#timestamped_entry{
timestamp = 4711,
- entry_type = test,
- entry = <<"some data">>},
+ entry = #plop_entry{type = test, data = Data1}},
+ S#state.privkey,
+ S#state.logid,
+ S#state.hashtree),
+ {_Tree1, SPT1} =
+ do_add(#timestamped_entry{
+ timestamp = 4712,
+ entry = #plop_entry{type = test, data = Data1}},
S#state.privkey,
S#state.logid,
S#state.hashtree),
- [?_assertEqual(<<"fixme:SPT">>, SPT)].
+ ?assertEqual(SPT, SPT1),
+
+ TE = #timestamped_entry{
+ timestamp = 0,
+ entry = #plop_entry{type = test, data = <<"some data">>}},
+ SPTeq1 = spt(S#state.logid, S#state.privkey, TE),
+ SPTeq2 = spt(S#state.logid, S#state.privkey, TE),
+ ?assertNotEqual(SPTeq1, SPTeq2). % DSA signatures differ!
diff --git a/test/eckey-public.pem b/test/eckey-public.pem
new file mode 100644
index 0000000..d952d7e
--- /dev/null
+++ b/test/eckey-public.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4qWq6afhBUi0OdcWUYhyJLNXTkGq
+Q9PMS5lqoCgkV2h1ZvpNjBH2u8UbgcOQwqDo66z6BWQJGolozZYmNHE2kQ==
+-----END PUBLIC KEY-----
diff --git a/test/eckey.pem b/test/eckey.pem
new file mode 100644
index 0000000..ed24cfa
--- /dev/null
+++ b/test/eckey.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIMM/FjZ4FSzfENTTwGpTve6CP+IVrY7p8OKV634uJI/foAoGCCqGSM49
+AwEHoUQDQgAE4qWq6afhBUi0OdcWUYhyJLNXTkGqQ9PMS5lqoCgkV2h1ZvpNjBH2
+u8UbgcOQwqDo66z6BWQJGolozZYmNHE2kQ==
+-----END EC PRIVATE KEY-----
diff --git a/test/plop_test.erl b/test/plop_test.erl
index 79dbbd3..cbbc85c 100644
--- a/test/plop_test.erl
+++ b/test/plop_test.erl
@@ -2,20 +2,20 @@
-include("plop.hrl").
-include_lib("eunit/include/eunit.hrl").
-start_stop_test_() ->
- {"The server can be started, stopped and is regsitered",
- {setup, fun start/0, fun stop/1, fun is_registered/1}}.
+%% start_stop_test_() ->
+%% {"The server can be started, stopped and is regsitered",
+%% {setup, fun start/0, fun stop/1, fun is_registered/1}}.
%% "Entries can be added and the STH changes."
%% FIXME: This way, if a test fails, we don't stop plop. The tests
%% must run and be validated in strict order though.
adding_verifying_test() ->
- Pid = start(),
- add(0),
- sth(0),
- add(1),
- %% sth(),
- stop(Pid).
+ %%Pid = start(),
+ Pubkey = plop:testing_get_pubkey(),
+ add(0, Pubkey),
+ add(1, Pubkey),
+ sth(0, Pubkey).
+ %%stop(Pid).
%%% Setup.
start() ->
@@ -31,49 +31,29 @@ is_registered(Pid) ->
?_assertEqual(Pid, whereis(plop))].
%%% Helpers.
-add(0) ->
- TestVector =
- <<1,247,141,118,3,148,171,128,29,143,106,97,200,179,204,166,242,98,70,185,231,
- 78,193,39,12,245,82,254,230,136,69,69,0,0,0,0,0,0,0,18,103,69,73,8,105,107,
- 47,97,130,137,92,201,148,11,68,203,103,216,217,249,38,109,208,23,55,107,21,
- 110,128,207,151,46,4,178,228,74,5,247,64,180,85,122,236,127,97,226,50,124,
- 212,251,227,65,248,18,36,124,252,103,24,35,99,180,207,126,63,116,149,21,86,
- 255,197,248,212,93,100,123,161,159,94,29,112,23,246,98,3,124,89,135,234,71,
- 246,21,93,152,214,209,58,25,52,132,219,22,0,38,237,226,118,1,168,86,218,18,
- 112,227,11,25,199,15,151,246,253,7,91,72,88,169,164,79,143,160,157,241,168,
- 15,230,1,216,93,67,24,230,106,203,61,115,100,172,238,165,236,198,222,33,126,
- 12,163,226,165,161,232,106,39,94,93,247,2,164,163,72,34,236,228,168,53,19,
- 128,111,78,34,54,166,95,78,11,131,241,191,254,82,225,72,68,111,229,169,24,75,
- 90,254,167,119,10,136,211,20,178,251,244,124,87,223,61,102,244,143,98,213,59,
- 217,84,80,64,22,209,1,63,64,185,63,13,115,43,36,143,93,19,206,234,100,181,
- 203,214,189,144,145,21,247,165,125,192,43,94,247,209,81,50,100>>,
+add(0, Pubkey) ->
+ Msg = <<"some data">>,
Entry = #timestamped_entry{timestamp = 4711,
- entry_type = test,
- entry = <<"some data">>},
+ entry = #plop_entry{type = test,
+ data = Msg}},
SPT = plop:add(Entry),
- ?assertEqual(TestVector, SPT);
-add(1) ->
- TestVector =
- <<1,247,141,118,3,148,171,128,29,143,106,97,200,179,204,166,242,98,70,185,231,
- 78,193,39,12,245,82,254,230,136,69,69,0,0,0,0,0,0,0,18,104,141,82,14,84,52,
- 131,244,51,145,16,7,238,168,117,8,184,95,165,94,116,234,87,145,43,39,223,243,
- 33,159,238,239,195,203,246,232,147,125,234,34,147,83,254,253,248,133,49,81,
- 80,7,104,23,24,147,24,116,147,183,20,58,165,53,147,196,226,250,135,18,115,
- 182,139,194,190,60,97,103,240,188,86,184,194,21,75,79,136,84,62,53,123,44,
- 236,244,24,190,207,193,42,156,230,135,174,90,195,89,174,185,228,129,148,78,
- 255,168,104,73,142,85,11,239,222,227,213,208,99,31,12,177,223,187,11,216,119,
- 29,231,67,82,140,103,181,173,71,246,112,57,121,153,204,1,249,251,172,26,77,
- 96,223,129,102,14,160,115,10,87,105,234,21,99,65,125,198,35,104,160,43,25,74,
- 159,64,236,226,126,208,88,199,60,12,88,36,214,174,110,147,215,142,1,205,77,
- 116,119,47,222,87,84,99,78,131,212,247,138,156,190,211,244,184,140,46,202,13,
- 217,28,20,109,8,129,62,226,37,51,123,94,151,151,47,96,111,122,118,178,242,14,
- 213,35,184,204,165,157,199,1,210,74,243,180,36,85,163,69,166,79,136>>,
+ <<Version:8, _LogID:256, Timestamp:64, Signature/binary>> = SPT,
+ Signed = <<1:8, 0:8, 4711:64, 2:16, Msg/binary>>,
+ ?assertEqual(1, Version),
+ ?assertEqual(4711, Timestamp),
+ ?assert(public_key:verify(Signed, sha256, Signature, Pubkey));
+
+add(1, Pubkey) ->
+ Msg = <<"some more data">>,
Entry = #timestamped_entry{timestamp = 4712,
- entry_type = test,
- entry = <<"some more data">>},
- SPT = plop:add(Entry),
- %%io:format(element(2, file:open("foo", write)), "~p", [SPT]),
- ?assertEqual(TestVector, SPT).
+ entry = #plop_entry{type = test,
+ data = Msg}},
+ <<Version:8, _LogID:256, Timestamp:64, Signature/binary>> = plop:add(Entry),
+ Signed = <<1:8, 0:8, 4712:64, 2:16, Msg/binary>>,
+ ?assertEqual(1, Version),
+ ?assertEqual(4712, Timestamp),
+ ?assert(public_key:verify(Signed, sha256, Signature, Pubkey)).
+
%% add(2) ->
%% TestVector = <<>>,
%% %% Same data as in 0, should not result in new database entry.
@@ -82,23 +62,13 @@ add(1) ->
%% ?assertEqual(TestVector, SPT),
%% ?assertEqual(fixme, fixme).
-sth(0) ->
- TestVector =
- <<0,0,0,0,0,0,0,1,0,0,0,0,0,0,18,103,93,90,159,157,211,129,96,54,161,145,226,
- 218,28,127,43,87,221,243,153,101,255,249,156,114,234,50,84,163,183,64,215,
- 227,16,126,61,255,54,243,5,185,250,149,18,30,228,16,48,168,252,213,27,205,
- 254,157,72,230,112,65,150,187,18,215,17,249,72,18,38,159,217,49,159,177,153,
- 175,86,139,158,29,24,202,126,203,88,216,19,205,237,172,48,9,113,228,231,170,
- 131,38,155,185,188,232,215,15,54,93,254,173,100,13,115,172,161,7,106,226,180,
- 168,81,245,47,10,59,14,25,26,23,80,11,227,147,115,216,173,93,63,232,50,213,
- 43,148,71,149,104,32,10,217,108,182,194,88,12,153,187,42,190,154,203,114,200,
- 24,137,106,65,51,25,162,178,24,199,155,215,208,115,5,239,64,189,69,0,196,55,
- 211,91,12,83,132,131,84,92,146,124,125,117,74,62,7,162,230,37,13,45,122,183,
- 112,207,227,240,152,190,181,168,96,210,252,59,144,12,141,46,18,18,51,226,14,
- 218,17,255,212,136,198,154,69,64,232,234,249,2,232,45,165,206,157,195,77,254,
- 126,173,10,12,184,21,55,111,183,15,2,251,177,220,139,35,20,148,219,137,78,
- 187,221,242,23,254,196,182,98,110,150,95,126,53,42,243,123,198,30,247,79,17,
- 172,129>>,
- STH = plop:sth(#sth{timestamp = 4711}),
- io:format(element(2, file:open("testdata", write)), "~p", [STH]),
- ?assertEqual(TestVector, STH).
+sth(0, Pubkey) ->
+ STH = plop:sth(#sth{}),
+ %%io:format(element(2, file:open("testdata", write)), "~p", [STH]),
+ <<Treesize:64,
+ Timestamp:64,
+ Roothash:256,
+ Signature/binary>> = STH,
+ ?assertEqual(2, Treesize),
+ Data = <<1:8, 1:8, Timestamp:64, Treesize:64, Roothash:256>>,
+ ?assert(public_key:verify(Data, sha256, Signature, Pubkey)).