diff options
author | Linus Nordberg <linus@nordu.net> | 2016-04-08 17:33:08 +0200 |
---|---|---|
committer | Linus Nordberg <linus@nordu.net> | 2016-04-08 17:33:08 +0200 |
commit | e173e2a050caa21725b588757becb84b3c56460a (patch) | |
tree | 558c8537fc85aeede3102b8c59a4f45ae9ca0add | |
parent | ed60e7e384560e8581d16c218ca629a7555beb1e (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.md | 37 | ||||
-rw-r--r-- | src/catlfish_app.erl | 1 | ||||
-rw-r--r-- | src/dnssecport.erl | 15 | ||||
-rw-r--r-- | src/v1.erl | 52 | ||||
-rw-r--r-- | test/catlfish-test-local-1.cfg | 1 | ||||
-rw-r--r-- | test/catlfish-test-local-merge-2.cfg | 1 | ||||
-rw-r--r-- | test/catlfish-test-local-merge.cfg | 1 | ||||
-rwxr-xr-x | tools/compileconfig.py | 17 |
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}} -> @@ -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/")) |