diff options
author | Linus Nordberg <linus@nordberg.se> | 2014-10-08 15:41:38 +0200 |
---|---|---|
committer | Linus Nordberg <linus@nordberg.se> | 2014-10-08 15:41:38 +0200 |
commit | e3fd2e3fc202ce18b90ac4ca96ac8264bed79569 (patch) | |
tree | 1c9736ab4def74aed1dd2c0975e96accf8f0e54c | |
parent | 645885d134798ff091769c0b69bac49f8f50b8a2 (diff) | |
parent | b0766332d2be4272a8d8065de684c61f1ad15c4d (diff) |
Merge branch 'plop-if-cleanup2' into origin-master
-rw-r--r-- | reltool.config | 6 | ||||
-rw-r--r-- | src/catlfish.erl | 163 |
2 files changed, 137 insertions, 32 deletions
diff --git a/reltool.config b/reltool.config index 434345c..80b374d 100644 --- a/reltool.config +++ b/reltool.config @@ -1,6 +1,5 @@ %% -*- mode: erlang -*- {sys, [ - {lib_dirs, [".."]}, {erts, [{mod_cond, derived}, {app_file, strip}]}, {app_file, strip}, {rel, "catlfish", "0.2.0-dev", @@ -12,6 +11,7 @@ ]}, {boot_rel, "catlfish"}, {excl_archive_filters, ["^include$","^priv$","^\\.git$"]}, - {app, catlfish, [{app_file, all}]} -%% {app, plop, [{mod_cond, app}, {incl_cond, include}, {lib_dir, "../plop"}]} + {app, catlfish, [{app_file, all}, {lib_dir, "."}]}, + {app, plop, [{app_file, all}, {lib_dir, "../plop"}]}, + {app, jiffy, [{app_file, all}, {lib_dir, "../jiffy"}]} ]}. diff --git a/src/catlfish.erl b/src/catlfish.erl index 2ba9d58..bd3c106 100644 --- a/src/catlfish.erl +++ b/src/catlfish.erl @@ -7,32 +7,129 @@ -define(PROTOCOL_VERSION, 0). --spec add_chain(binary(), list()) -> list(). +%%-type signature_type() :: certificate_timestamp | tree_hash | test. % uint8 +-type entry_type() :: x509_entry | precert_entry | test. % uint16 +-type leaf_type() :: timestamped_entry | test. % uint8 +-type leaf_version() :: v1 | v2. % uint8 + +-record(mtl, {leaf_version :: leaf_version(), + leaf_type :: leaf_type(), + entry :: timestamped_entry()}). +-type mtl() :: #mtl{}. + +-record(timestamped_entry, {timestamp :: integer(), + entry_type :: entry_type(), + signed_entry :: binary(), + extensions = <<>> :: binary()}). +-type timestamped_entry() :: #timestamped_entry{}. + +-spec serialise(mtl() | timestamped_entry()) -> binary(). +serialise(#timestamped_entry{timestamp = Timestamp} = E) -> + list_to_binary( + [<<Timestamp:64>>, + serialise_entry_type(E#timestamped_entry.entry_type), + encode_tls_vector(E#timestamped_entry.signed_entry, 3), + encode_tls_vector(E#timestamped_entry.extensions, 2)]); +serialise(#mtl{leaf_version = LeafVersion, + leaf_type = LeafType, + entry = TimestampedEntry}) -> + list_to_binary( + [serialise_leaf_version(LeafVersion), + serialise_leaf_type(LeafType), + serialise(TimestampedEntry)]). + +serialise_leaf_version(v1) -> + <<0:8>>; +serialise_leaf_version(v2) -> + <<1:8>>. + +serialise_leaf_type(timestamped_entry) -> + <<0:8>>. +%% serialise_leaf_type(_) -> +%% <<>>. + +serialise_entry_type(x509_entry) -> + <<0:16>>; +serialise_entry_type(precert_entry) -> + <<1:16>>. + +serialise_signature_type(certificate_timestamp) -> + <<0:8>>; +serialise_signature_type(tree_hash) -> + <<1:8>>. + +build_mtl(Timestamp, LeafCert) -> + TSE = #timestamped_entry{timestamp = Timestamp, + entry_type = x509_entry, + signed_entry = LeafCert}, + MTL = #mtl{leaf_version = v1, + leaf_type = timestamped_entry, + entry = TSE}, + serialise(MTL). + +-spec add_chain(binary(), [binary()]) -> nonempty_string(). 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})). + EntryHash = crypto:hash(sha256, LeafCert), + TimestampedEntry = + case plop:get(EntryHash) of + notfound -> + Timestamp = plop:generate_timestamp(), + TSE = #timestamped_entry{timestamp = Timestamp, + entry_type = x509_entry, + signed_entry = LeafCert}, + MTL = #mtl{leaf_version = v1, + leaf_type = timestamped_entry, + entry = TSE}, + ok = plop:add( + serialise_logentry(Timestamp, LeafCert, CertChain), + ht:leaf_hash(serialise(MTL)), + crypto:hash(sha256, LeafCert)), + TSE; + {_Index, _MTLHash, Entry} -> + <<Timestamp:64, _LogEntry/binary>> = Entry, + %% TODO: Perform a costly db consistency check against + %% unpacked LogEntry (w/ LeafCert and CertChain) + #timestamped_entry{timestamp = Timestamp, + entry_type = x509_entry, + signed_entry = LeafCert} + end, + SCT_sig = + plop:spt(list_to_binary([<<?PROTOCOL_VERSION:8>>, + serialise_signature_type(certificate_timestamp), + serialise(TimestampedEntry)])), + binary_to_list( + jiffy:encode( + {[{sct_version, ?PROTOCOL_VERSION}, + {id, base64:encode(plop:get_logid())}, + {timestamp, TimestampedEntry#timestamped_entry.timestamp}, + {extensions, base64:encode(<<>>)}, + {signature, base64:encode(plop:serialise(SCT_sig))}]})). + +-spec serialise_logentry(integer(), binary(), [binary()]) -> binary(). +serialise_logentry(Timestamp, LeafCert, CertChain) -> + list_to_binary( + [<<Timestamp:64>>, + list_to_binary( + [encode_tls_vector(LeafCert, 3), + encode_tls_vector( + list_to_binary( + [encode_tls_vector(X, 3) || X <- CertChain]), 3)])]). -spec entries(non_neg_integer(), non_neg_integer()) -> list(). entries(Start, End) -> - encode_entries(plop:get(Start, End)). + binary_to_list( + jiffy:encode({[{entries, x_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)}, + {ok, {Entry, Path}} -> + {Timestamp, LeafCertVector, CertChainVector} = unpack_entry(Entry), + MTL = build_mtl(Timestamp, LeafCertVector), + {[{leaf_input, base64:encode(MTL)}, + {extra_data, base64:encode(CertChainVector)}, {audit_path, [base64:encode(X) || X <- Path]}]}; {notfound, Msg} -> {[{success, false}, @@ -40,20 +137,28 @@ entry_and_proof(Index, TreeSize) -> end)). %% Private functions. --spec encode_entries([{mtl(), binary()}]) -> list(). -encode_entries(Entries) -> - binary_to_list(jiffy:encode({[{entries, unpack_entries(Entries)}]})). +unpack_entry(Entry) -> + <<Timestamp:64, LogEntry/binary>> = Entry, + {LeafCertVector, CertChainVector} = decode_tls_vector(LogEntry, 3), + {Timestamp, LeafCertVector, CertChainVector}. --spec unpack_entries([{mtl(), binary()}]) -> list(). -unpack_entries([]) -> +-spec x_entries([{non_neg_integer(), binary(), binary()}]) -> list(). +x_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) -> +x_entries([H|T]) -> + [_Index, _Hash, Entry] = H, + {Timestamp, LeafCertVector, CertChainVector} = unpack_entry(Entry), + MTL = build_mtl(Timestamp, LeafCertVector), + [{[{leaf_input, base64:encode(MTL)}, {extra_data, base64:encode(CertChainVector)}]} | + x_entries(T)]. + +-spec encode_tls_vector(binary(), non_neg_integer()) -> binary(). +encode_tls_vector(Binary, LengthLen) -> Length = byte_size(Binary), <<Length:LengthLen/integer-unit:8, Binary/binary>>. + +-spec decode_tls_vector(binary(), non_neg_integer()) -> {binary(), binary()}. +decode_tls_vector(Binary, LengthLen) -> + <<Length:LengthLen/integer-unit:8, Rest/binary>> = Binary, + <<ExtractedBinary:Length/binary-unit:8, Rest2/binary>> = Rest, + {ExtractedBinary, Rest2}. |