summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/catlfish.erl59
-rw-r--r--src/v1.erl61
2 files changed, 64 insertions, 56 deletions
diff --git a/src/catlfish.erl b/src/catlfish.erl
new file mode 100644
index 0000000..2ba9d58
--- /dev/null
+++ b/src/catlfish.erl
@@ -0,0 +1,59 @@
+%%% Copyright (c) 2014, NORDUnet A/S.
+%%% See LICENSE for licensing information.
+
+-module(catlfish).
+-export([add_chain/2, entries/2, entry_and_proof/2]).
+-include("$CTROOT/plop/include/plop.hrl").
+
+-define(PROTOCOL_VERSION, 0).
+
+-spec add_chain(binary(), list()) -> list().
+add_chain(LeafCert, CertChain) ->
+ Entry = #plop_entry{type = x509, data = LeafCert},
+ EDVectors = [serialise_tls_vector(X, 3) || X <- CertChain],
+ ExtraData = serialise_tls_vector(list_to_binary(EDVectors), 3),
+ SPT = plop:add(#timestamped_entry{entry = Entry}, ExtraData),
+ R = [{sct_version, ?PROTOCOL_VERSION},
+ {id, base64:encode(SPT#spt.logid)},
+ {timestamp, SPT#spt.timestamp},
+ {extensions, base64:encode("")},
+ {signature, base64:encode(plop:serialise(SPT#spt.signature))}],
+ binary_to_list(jiffy:encode({R})).
+
+-spec entries(non_neg_integer(), non_neg_integer()) -> list().
+entries(Start, End) ->
+ encode_entries(plop:get(Start, End)).
+
+-spec entry_and_proof(non_neg_integer(), non_neg_integer()) -> list().
+entry_and_proof(Index, TreeSize) ->
+ binary_to_list(
+ jiffy:encode(
+ case plop:inclusion_and_entry(Index, TreeSize) of
+ {ok, MTL, Extra, Path} ->
+ {[{leaf_input, base64:encode(plop:serialise(MTL))},
+ %% Extra data is already in TLS vector format.
+ {extra_data, base64:encode(Extra)},
+ {audit_path, [base64:encode(X) || X <- Path]}]};
+ {notfound, Msg} ->
+ {[{success, false},
+ {error_message, list_to_binary(Msg)}]}
+ end)).
+
+%% Private functions.
+-spec encode_entries([{mtl(), binary()}]) -> list().
+encode_entries(Entries) ->
+ binary_to_list(jiffy:encode({[{entries, unpack_entries(Entries)}]})).
+
+-spec unpack_entries([{mtl(), binary()}]) -> list().
+unpack_entries([]) ->
+ [];
+unpack_entries([H|T]) ->
+ {MTL, Extra} = H,
+ LeafInput = base64:encode(plop:serialise(MTL)),
+ ExtraData = base64:encode(Extra),
+ [{[{leaf_input, LeafInput}, {extra_data, ExtraData}]} | unpack_entries(T)].
+
+-spec serialise_tls_vector(binary(), non_neg_integer()) -> binary().
+serialise_tls_vector(Binary, LengthLen) ->
+ Length = byte_size(Binary),
+ <<Length:LengthLen/integer-unit:8, Binary/binary>>.
diff --git a/src/v1.erl b/src/v1.erl
index 5f0afc6..304b0a8 100644
--- a/src/v1.erl
+++ b/src/v1.erl
@@ -8,11 +8,8 @@
-export(['add-chain'/3, 'add-pre-chain'/3, 'get-sth'/3,
'get-sth-consistency'/3, 'get-proof-by-hash'/3, 'get-entries'/3,
'get-roots'/3, 'get-entry-and-proof'/3]).
-%% Testing -- FIXME: remove
--export([hello/3]).
-include("$CTROOT/plop/include/plop.hrl").
--define(PROTOCOL_VERSION, 0).
%% Public functions, i.e. part of URL.
'add-chain'(SessionID, _Env, Input) ->
@@ -25,16 +22,7 @@
html("add-chain: invalid base64-encoded chain: ",
[ChainBase64]);
[LeafCert | CertChain] ->
- Entry = #plop_entry{type = x509, data = LeafCert},
- SPT = plop:add(#timestamped_entry{entry = Entry},
- list_to_binary(CertChain)),
- R2 = [{sct_version, ?PROTOCOL_VERSION},
- {id, base64:encode(SPT#spt.logid)},
- {timestamp, SPT#spt.timestamp},
- {extensions, base64:encode("")},
- {signature, base64:encode(
- plop:serialise(SPT#spt.signature))}],
- binary_to_list(jiffy:encode({R2}));
+ catlfish:add_chain(LeafCert, CertChain);
Invalid ->
html("add-chain: chain is not a list: ", [Invalid])
end;
@@ -109,7 +97,7 @@
deliver(SessionID, R).
'get-entries'(SessionID, _Env, Input) ->
- %% TODO: Limit the number of returned entreis (i.e. start-end) to
+ %% TODO: Limit the number of returned entries (i.e. start-end) to
%% something reasonable.
R = case lists:sort(httpd:parse_query(Input)) of
[{"end", EndInput}, {"start", StartInput}] ->
@@ -117,7 +105,7 @@
{End, _} = string:to_integer(EndInput),
case lists:member(error, [Start, End]) of
true -> html("get-entries: bad input:", [Start, End]);
- false -> encode_entries(plop:get(Start, End))
+ false -> catlfish:entries(Start, End)
end;
_ -> html("get-entries: bad input:", Input)
end,
@@ -132,20 +120,7 @@
true ->
html("get-entry-and-proof: not integers: ",
[IndexInput, TreeSizeInput]);
- false ->
- binary_to_list(
- jiffy:encode(
- case plop:inclusion_and_more(Index, TreeSize) of
- {ok, Leaf, Chain, Path} ->
- {[{leaf_input,
- base64:encode(plop:serialise(Leaf))},
- {extra_data, base64:encode(Chain)},
- {audit_path,
- [base64:encode(X) || X <- Path]}]};
- {notfound, Msg} ->
- {[{success, false},
- {error_message, list_to_binary(Msg)}]}
- end))
+ false -> catlfish:entry_and_proof(Index, TreeSize)
end;
_ -> html("get-entry-and-proof: bad input:", Input)
end,
@@ -155,33 +130,7 @@
R = [{certificates, []}], % NIY.
deliver(SessionID, binary_to_list(jiffy:encode({R}))).
-%% For testing. FIXME: Remove.
-hello(SessionID, Env, Input) ->
- Query = httpd:parse_query(Input),
- mod_esi:deliver(SessionID, io_lib:format(
- "Content-Type: text/html\r\n\r\n" ++
- "<html><body>hello again, erlang world" ++
- "<p>SessionID: ~p~n" ++
- "<p>Env: ~p~n" ++
- "<p>Input, raw: ~p~n" ++
- "<p>Input, parsed: ~p~n" ++
- "</body></html>",
- [SessionID, Env, Input, Query])).
-
%% Private functions.
--spec encode_entries([{mtl(), binary()}]) -> list().
-encode_entries(Entries) ->
- binary_to_list(jiffy:encode({[{entries, unpack_entries(Entries)}]})).
-
--spec unpack_entries([{mtl(), binary()}]) -> list().
-unpack_entries([]) ->
- [];
-unpack_entries([H|T]) ->
- {MTL, Extra} = H,
- LeafInput = base64:encode(plop:serialise(MTL)),
- ExtraData = base64:encode(Extra),
- [{[{leaf_input, LeafInput}, {extra_data, ExtraData}]} | unpack_entries(T)].
-
html(Text, Input) ->
io_lib:format(
"Content-Type: text/html\r\n\r\n" ++
@@ -191,7 +140,7 @@ html(Text, Input) ->
"</body></html>~n", [Text, Input]).
niy(S) ->
- mod_esi:deliver(S, html("NIY - Not Yet Implemented|", [])).
+ mod_esi:deliver(S, html("NIY - Not Implemented Yet|", [])).
-spec deliver(any(), string()) -> ok | {error, _Reason}.
deliver(Session, Data) ->