summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Nordberg <linus@nordu.net>2016-04-08 17:33:08 +0200
committerLinus Nordberg <linus@nordu.net>2016-04-08 17:33:08 +0200
commite173e2a050caa21725b588757becb84b3c56460a (patch)
tree558c8537fc85aeede3102b8c59a4f45ae9ca0add
parented60e7e384560e8581d16c218ca629a7555beb1e (diff)
Get submitting and storing working.
Add README.dnssec. Do start the dnssecport server. Add config option 'trust_anchors_file'. Pass correct data to validation server. Change URL for submitting to match draft (add-rr-chain). Make add-rr-chain take a base64-encoded string of RR's instead of JSON list with one RR per entry. TODO: Make the python tools know enough DNS to be able to verify SCT's and such (i.e. 'make tests').
-rw-r--r--README-dnssec.md37
-rw-r--r--src/catlfish_app.erl1
-rw-r--r--src/dnssecport.erl15
-rw-r--r--src/v1.erl52
-rw-r--r--test/catlfish-test-local-1.cfg1
-rw-r--r--test/catlfish-test-local-merge-2.cfg1
-rw-r--r--test/catlfish-test-local-merge.cfg1
-rwxr-xr-xtools/compileconfig.py17
8 files changed, 83 insertions, 42 deletions
diff --git a/README-dnssec.md b/README-dnssec.md
new file mode 100644
index 0000000..c0da6b1
--- /dev/null
+++ b/README-dnssec.md
@@ -0,0 +1,37 @@
+# Notes on DNSSEC Transparency
+
+## Protocol
+
+DNSSEC Transparency is implemented as described in
+draft-zhang-trans-ct-dnssec-03 with the following changes.
+
+- Submissions MUST include RRSIG RR's for all DS and DNSKEY RR's
+
+ - Log implementation is made easier since the log doesn't have to
+ make DNS queries.
+
+ - The system as a whole is made more predictable by including data
+ from the DNS from a single vantage point.
+
+- Base URL is changed from
+ https://<log server>/ct/v1/
+ to
+ https://<log server>/dt/v1/
+
+ - No risk for conflict with CT's namespace.
+ - The type of service is obvious from looking at the URL.
+
+- Submission format is changed from an array of base64-encoded RR's to
+ a single string object with a base64-encoded RRset. Note that the
+ order of the first two records is still important -- the first RR in
+ the RRset MUST be the DS record under submission, the next record
+ MUST be the RRSIG covering the DS record.
+
+ - The length of an RR is encoded in the data so RR's don't need the
+ framing provided by a JSON array.
+
+## Status
+
+## Open issues
+
+- TLS vectors, should we really use them?
diff --git a/src/catlfish_app.erl b/src/catlfish_app.erl
index eef74d6..d14fd22 100644
--- a/src/catlfish_app.erl
+++ b/src/catlfish_app.erl
@@ -13,6 +13,7 @@
%% ===================================================================
start(normal, Args) ->
+ dnssecport:start_link(),
catlfish:init_cache_table(),
catlfish_sup:start_link(Args).
diff --git a/src/dnssecport.erl b/src/dnssecport.erl
index 30c8c9e..acdc5c4 100644
--- a/src/dnssecport.erl
+++ b/src/dnssecport.erl
@@ -23,9 +23,16 @@ validate(Data) ->
-record(state, {port :: port()}).
+-spec trust_anchors() -> string().
+trust_anchors() ->
+ case application:get_env(catlfish, trust_anchors_file) of
+ {ok, Filename} -> Filename;
+ undefined -> []
+ end.
+
init(Program) ->
lager:debug("starting dnssec service"),
- Port = create_port(Program, []), % TODO: Pass path to trust root file.
+ Port = create_port(Program, [trust_anchors()]),
{ok, #state{port = Port}}.
decode_response(Response) ->
@@ -38,9 +45,9 @@ handle_call(stop, _From, State) ->
handle_call({validate, Data}, _From, State) ->
case State#state.port of
undefined ->
- {error, noport};
+ {reply, {error, noport}, State};
Port when is_port(Port) ->
- Port ! {self(), {command, dns:encode_rrset(Data)}},
+ Port ! {self(), {command, Data}},
receive
{Port, {data, Response}} ->
case decode_response(list_to_binary(Response)) of
@@ -50,6 +57,8 @@ handle_call({validate, Data}, _From, State) ->
dns:encode_rrset(Chain)],
{reply, {ok, R}, State};
{ok, Error, _} ->
+ lager:debug("DNSSEC validation failed with ~p",
+ [Error]),
{reply, {error, Error}, State}
end;
{Port, {exit_status, ExitStatus}} ->
diff --git a/src/v1.erl b/src/v1.erl
index ef9aadd..72d0112 100644
--- a/src/v1.erl
+++ b/src/v1.erl
@@ -30,9 +30,9 @@ check_valid_sth() ->
end.
%% Public functions, i.e. part of URL.
-request(post, ?APPURL_CT_V1, "add-ds-rr", Input) ->
+request(post, ?APPURL_CT_V1, "add-rr-chain", Input) ->
check_valid_sth(),
- add_ds(Input);
+ add_rr_chain(Input);
request(get, ?APPURL_CT_V1, "get-sth", _Query) ->
check_valid_sth(),
@@ -147,37 +147,27 @@ internalerror(Text) ->
"~s~n" ++
"</body></html>~n", [Text])}.
--spec add_ds(any()) -> any().
-add_ds(Input) ->
+-spec add_rr_chain(any()) -> any().
+add_rr_chain(Input) ->
case (catch mochijson2:decode(Input)) of
{error, E} ->
- err400("add-ds-rr: bad input:", E);
- {struct, [{<<"chain">>, List}]} ->
- case decode_chain(List) of
- {invalid, ErrText} ->
- err400(io:format("add-ds-rr: ~p", [ErrText]), List);
- Data when is_list(Data) ->
- add_ds_helper(Data);
- _ ->
- err400("add-ds-rr: missing one or more entries", List)
+ err400("add-rr-chain: bad input:", E);
+ {struct, [{<<"chain">>, B64}]} ->
+ case (catch base64:decode(B64)) of
+ {'EXIT', _} ->
+ err400("add-rr-chain: invalid base64-encoding:", B64);
+ Data ->
+ case dnssecport:validate(Data) of
+ {ok, [DS | Chain]} ->
+ lager:debug("succesful DNSSEC validation"),
+ success(catlfish:add_chain(DS, Chain, normal));
+ {error, ErrorCode} ->
+ err400(io_lib:format(
+ "add-rr-chain: invalid DS record: ~p",
+ [ErrorCode]),
+ Data)
+ end
end;
_ ->
- err400("add-ds-rr: missing input: chain", Input)
- end.
-
-decode_chain(List) ->
- case (catch [base64:decode(X) || X <- List]) of
- {'EXIT', _} ->
- {invalid, "invalid base64-encoding"};
- L ->
- L
- end.
-
-add_ds_helper(Data) ->
- case dnssecport:validate(Data) of
- {ok, [DS | Chain]} ->
- success(catlfish:add_chain(DS, Chain, normal));
- {error, ErrorCode} ->
- err400(io:format("add-ds-rr: invalid DS record: ~p", [ErrorCode]),
- Data)
+ err400("add-rr-chain: missing input: chain", Input)
end.
diff --git a/test/catlfish-test-local-1.cfg b/test/catlfish-test-local-1.cfg
index fbd7e4b..2c5814d 100644
--- a/test/catlfish-test-local-1.cfg
+++ b/test/catlfish-test-local-1.cfg
@@ -14,6 +14,7 @@ publicaddresses:
paths:
configdir: .
+ trust_anchors_file: tests/trust_anchors
knownroots: tests/known_roots
https_certfile: tests/httpscert/httpscert-1.pem
https_keyfile: tests/httpscert/httpskey-1.pem
diff --git a/test/catlfish-test-local-merge-2.cfg b/test/catlfish-test-local-merge-2.cfg
index 28c4eda..ebcc45b 100644
--- a/test/catlfish-test-local-merge-2.cfg
+++ b/test/catlfish-test-local-merge-2.cfg
@@ -8,6 +8,7 @@ nodename: merge-2
paths:
configdir: .
+ trust_anchors_file: tests/trust_anchors
knownroots: tests/known_roots
mergedb: tests/mergedb-secondary
https_certfile: tests/httpscert/httpscert-1.pem
diff --git a/test/catlfish-test-local-merge.cfg b/test/catlfish-test-local-merge.cfg
index 766c872..0e2396d 100644
--- a/test/catlfish-test-local-merge.cfg
+++ b/test/catlfish-test-local-merge.cfg
@@ -7,4 +7,5 @@ paths:
logpublickey: tests/keys/logkey.pem
privatekeys: tests/privatekeys
verifycert_bin: ../verifycert.erl
+ trust_anchors_file: tests/trust_anchors
known_roots: tests/known_roots/
diff --git a/tools/compileconfig.py b/tools/compileconfig.py
index e747fad..c236e1d 100755
--- a/tools/compileconfig.py
+++ b/tools/compileconfig.py
@@ -147,13 +147,13 @@ def allowed_clients_mergesecondary(primarymergenode):
def allowed_clients_public():
noauth = Symbol("noauth")
return [
- ("/open/gaol/v1/add-blob", noauth),
- ("/open/gaol/v1/get-sth", noauth),
- ("/open/gaol/v1/get-sth-consistency", noauth),
- ("/open/gaol/v1/get-proof-by-hash", noauth),
- ("/open/gaol/v1/get-entries", noauth),
- ("/open/gaol/v1/get-entry-and-proof", noauth),
- ("/open/gaol/v1/get-roots", noauth),
+ ("/dt/v1/add-rr-chain", noauth),
+ ("/dt/v1/get-sth", noauth),
+ ("/dt/v1/get-sth-consistency", noauth),
+ ("/dt/v1/get-proof-by-hash", noauth),
+ ("/dt/v1/get-entries", noauth),
+ ("/dt/v1/get-entry-and-proof", noauth),
+ ("/dt/v1/get-roots", noauth),
]
def allowed_clients_signing(frontendnodenames, primarymergenode):
@@ -210,7 +210,8 @@ def gen_config(nodename, config, localconfig):
plopconfig = []
if nodetype & set(["frontendnodes", "mergenodes"]):
- catlfishconfig.append((Symbol("known_roots_path"), localconfig["paths"]["knownroots"]))
+ catlfishconfig.append((Symbol("trust_anchors_file"),
+ localconfig["paths"]["trust_anchors_file"]))
if "frontendnodes" in nodetype:
if "sctcaching" in options:
catlfishconfig.append((Symbol("sctcache_root_path"), paths["db"] + "sctcache/"))