%%% 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), <>.