Annotate

mod_s2s_auth_dane/mod_s2s_auth_dane.lua @ 1307:71dd991c94e7

mod_manifesto: Add ad-hoc command to enable "manifesto mode"
author Florian Zeitz <florob@babelmonkeys.de>
date Mon, 17 Feb 2014 20:39:48 +0100
parent 1269:69d42d2427f7
child 1324:853a382c9bd6
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
1 -- mod_s2s_auth_dane
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
2 --
1269
69d42d2427f7 mod_s2s_auth_dane: Fix typo in comment (thanks albert)
Kim Alvefur <zash@zash.se>
parents: 1266
diff changeset
3 -- Between the DNS lookup and the certificate validation, there is a race condition.
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
4 -- Solving that probably requires changes to mod_s2s, like using util.async
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
5
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
6
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
7 module:set_global();
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
8
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
9 local dns_lookup = require"net.adns".lookup;
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
10 local hashes = require"util.hashes";
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
11 local base64 = require"util.encodings".base64;
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
12
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
13 local s2sout = module:depends"s2s".route_to_new_session.s2sout;
1266
51e7a4bbd70b mod_s2s_auth_dane: Style fixes
Kim Alvefur <zash@zash.se>
parents: 1265
diff changeset
14 local _try_connect = s2sout.try_connect;
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
15
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
16 local pat = "%-%-%-%-%-BEGIN ([A-Z ]+)%-%-%-%-%-\r?\n"..
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
17 "([0-9A-Za-z=+/\r\n]*)\r?\n%-%-%-%-%-END %1%-%-%-%-%-";
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
18 local function pem2der(pem)
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
19 local typ, data = pem:match(pat);
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
20 if typ and data then
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
21 return base64.decode(data), typ;
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
22 end
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
23 end
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
24
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
25 -- TODO Things to test/handle:
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
26 -- Negative or bogus answers
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
27 -- No SRV records
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
28
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
29 function s2sout.try_connect(host_session, connect_host, connect_port, err)
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
30 local srv_hosts = host_session.srv_hosts;
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
31 local srv_choice = host_session.srv_choice;
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
32 if srv_hosts and srv_hosts.answer.secure and not srv_hosts[srv_choice].dane then
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
33 dns_lookup(function(answer)
1262
1e84eebf3f46 mod_s2s_auth_dane: Invalidate trust if there are TLSA records but no matches, or bogus results
Kim Alvefur <zash@zash.se>
parents: 1261
diff changeset
34 if answer and ( #answer > 0 or answer.bogus ) then
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
35 srv_hosts[srv_choice].dane = answer;
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
36 for i, tlsa in ipairs(answer) do
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
37 module:log("debug", "TLSA %s", tostring(tlsa));
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
38 end
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
39 end
1266
51e7a4bbd70b mod_s2s_auth_dane: Style fixes
Kim Alvefur <zash@zash.se>
parents: 1265
diff changeset
40 end, ("_%d._tcp.%s"):format(connect_port, connect_host), "TLSA");
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
41 end
1266
51e7a4bbd70b mod_s2s_auth_dane: Style fixes
Kim Alvefur <zash@zash.se>
parents: 1265
diff changeset
42 return _try_connect(host_session, connect_host, connect_port, err);
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
43 end
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
44
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
45 module:hook("s2s-check-certificate", function(event)
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
46 local session, cert = event.session, event.cert;
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
47 local srv_hosts = session.srv_hosts;
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
48 local srv_choice = session.srv_choice;
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
49 local choosen = srv_hosts and srv_hosts[srv_choice];
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
50 if choosen and choosen.dane then
1266
51e7a4bbd70b mod_s2s_auth_dane: Style fixes
Kim Alvefur <zash@zash.se>
parents: 1265
diff changeset
51 local use, select, match, tlsa, certdata, match_found;
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
52 for i, rr in ipairs(choosen.dane) do
1266
51e7a4bbd70b mod_s2s_auth_dane: Style fixes
Kim Alvefur <zash@zash.se>
parents: 1265
diff changeset
53 tlsa = rr.tlsa;
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
54 module:log("debug", "TLSA %s", tostring(tlsa));
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
55 use, select, match, certdata = tlsa.use, tlsa.select, tlsa.match;
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
56
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
57 if use == 1 or use == 3 then
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
58
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
59 if select == 0 then
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
60 certdata = pem2der(cert:pem());
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
61 elseif select == 1 then
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
62 certdata = pem2der(cert:pubkey());
1261
6a37bd22c8df mod_s2s_auth_dane: Warn about unsupported DANE params
Kim Alvefur <zash@zash.se>
parents: 1258
diff changeset
63 else
6a37bd22c8df mod_s2s_auth_dane: Warn about unsupported DANE params
Kim Alvefur <zash@zash.se>
parents: 1258
diff changeset
64 module:log("warn", "DANE selector %d is unsupported", select);
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
65 end
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
66 if match == 1 then
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
67 certdata = hashes.sha256(certdata);
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
68 elseif match == 2 then
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
69 certdata = hashes.sha512(certdata);
1261
6a37bd22c8df mod_s2s_auth_dane: Warn about unsupported DANE params
Kim Alvefur <zash@zash.se>
parents: 1258
diff changeset
70 elseif match ~= 0 then
6a37bd22c8df mod_s2s_auth_dane: Warn about unsupported DANE params
Kim Alvefur <zash@zash.se>
parents: 1258
diff changeset
71 module:log("warn", "DANE match rule %d is unsupported", match);
1266
51e7a4bbd70b mod_s2s_auth_dane: Style fixes
Kim Alvefur <zash@zash.se>
parents: 1265
diff changeset
72 certdata = nil;
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
73 end
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
74
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
75 -- Should we check if the cert subject matches?
1261
6a37bd22c8df mod_s2s_auth_dane: Warn about unsupported DANE params
Kim Alvefur <zash@zash.se>
parents: 1258
diff changeset
76 if certdata and certdata == tlsa.data then
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
77 (session.log or module._log)("info", "DANE validation successful");
1266
51e7a4bbd70b mod_s2s_auth_dane: Style fixes
Kim Alvefur <zash@zash.se>
parents: 1265
diff changeset
78 session.cert_identity_status = "valid";
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
79 if use == 3 then
1266
51e7a4bbd70b mod_s2s_auth_dane: Style fixes
Kim Alvefur <zash@zash.se>
parents: 1265
diff changeset
80 session.cert_chain_status = "valid";
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
81 -- for usage 1 the chain has to be valid already
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
82 end
1266
51e7a4bbd70b mod_s2s_auth_dane: Style fixes
Kim Alvefur <zash@zash.se>
parents: 1265
diff changeset
83 match_found = true;
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
84 break;
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
85 end
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
86 else
1261
6a37bd22c8df mod_s2s_auth_dane: Warn about unsupported DANE params
Kim Alvefur <zash@zash.se>
parents: 1258
diff changeset
87 module:log("warn", "DANE %s is unsupported", tlsa:getUsage() or ("usage "..tostring(use)));
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
88 -- TODO Ca checks needs to loop over the chain and stuff
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
89 end
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
90 end
1262
1e84eebf3f46 mod_s2s_auth_dane: Invalidate trust if there are TLSA records but no matches, or bogus results
Kim Alvefur <zash@zash.se>
parents: 1261
diff changeset
91 if not match_found then
1265
020165014e56 mod_s2s_auth_dane: Fix wording on validation failure
Kim Alvefur <zash@zash.se>
parents: 1262
diff changeset
92 (session.log or module._log)("warn", "DANE validation failed");
1262
1e84eebf3f46 mod_s2s_auth_dane: Invalidate trust if there are TLSA records but no matches, or bogus results
Kim Alvefur <zash@zash.se>
parents: 1261
diff changeset
93 session.cert_identity_status = "invalid";
1e84eebf3f46 mod_s2s_auth_dane: Invalidate trust if there are TLSA records but no matches, or bogus results
Kim Alvefur <zash@zash.se>
parents: 1261
diff changeset
94 session.cert_chain_status = "invalid";
1e84eebf3f46 mod_s2s_auth_dane: Invalidate trust if there are TLSA records but no matches, or bogus results
Kim Alvefur <zash@zash.se>
parents: 1261
diff changeset
95 end
1258
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
96 end
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
97 end);
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
98
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
99 function module.unload()
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
100 s2sout.try_connect = _try_connect;
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
101 end
fc82d8eded7d mod_s2s_auth_dane: Experimental DANE implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
102