Annotate

mod_s2s_auth_posh/mod_s2s_auth_posh.lua @ 3198:f3e452b43cfe

mod_s2s_auth_posh: PKIX over Secure HTTP
author Kim Alvefur <zash@zash.se>
date Wed, 21 May 2014 23:01:47 +0200
child 3199:cb7c24305ed2
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
3198
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
1 -- Copyright (C) 2013 - 2014 Tobias Markmann
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
2 -- This file is MIT/X11 licensed.
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
3 --
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
4 -- Implements authentication via POSH (PKIX over Secure HTTP)
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
5 -- http://tools.ietf.org/html/draft-miller-posh-03
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
6 --
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
7 module:set_global();
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
8 --local https = require 'ssl.https'
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
9 --local http = require "socket.http";
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
10 local json = require 'util.json'
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
11 local serialization = require 'util.serialization'
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
12
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
13 local nameprep = require "util.encodings".stringprep.nameprep;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
14 local to_unicode = require "util.encodings".idna.to_unicode;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
15 local cert_verify_identity = require "util.x509".verify_identity;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
16 local der2pem = require"util.x509".der2pem;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
17 local base64 = require"util.encodings".base64;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
18
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
19 local function posh_lookup(host_session, resume)
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
20 -- do nothing if posh info already exists
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
21 if host_session.posh ~= nil then return end
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
22
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
23 (host_session.log or module._log)("debug", "DIRECTION: %s", tostring(host_session.direction));
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
24
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
25 local target_host = false;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
26 if host_session.direction == "incoming" then
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
27 target_host = host_session.from_host;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
28 elseif host_session.direction == "outgoing" then
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
29 target_host = host_session.to_host;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
30 end
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
31
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
32 local url = "https://"..target_host.."/.well-known/posh._xmpp-server._tcp.json"
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
33
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
34 (host_session.log or module._log)("debug", "Request POSH information for %s", tostring(target_host));
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
35 local request = http.request(url, nil, function(response, code, req)
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
36 (host_session.log or module._log)("debug", "Received POSH response");
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
37 local jwk = json.decode(response);
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
38 if not jwk then
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
39 (host_session.log or module._log)("error", "POSH response is not valid JSON!");
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
40 (host_session.log or module._log)("debug", tostring(response));
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
41 end
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
42 host_session.posh = {};
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
43 host_session.posh.jwk = jwk;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
44 resume()
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
45 end)
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
46 return true;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
47 end
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
48
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
49 function module.add_host(module)
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
50 local function on_new_s2s(event)
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
51 local host_session = event.origin;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
52 if host_session.type == "s2sout" or host_session.type == "s2sin" or host_session.posh ~= nil then return end -- Already authenticated
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
53
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
54 host_session.log("debug", "Pausing connection until POSH lookup is completed");
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
55 host_session.conn:pause()
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
56 local function resume()
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
57 host_session.log("debug", "POSH lookup completed, resuming connection");
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
58 host_session.conn:resume()
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
59 end
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
60 if not posh_lookup(host_session, resume) then
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
61 resume();
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
62 end
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
63 end
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
64
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
65 -- New outgoing connections
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
66 module:hook("stanza/http://etherx.jabber.org/streams:features", on_new_s2s, 501);
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
67 module:hook("s2sout-authenticate-legacy", on_new_s2s, 200);
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
68
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
69 -- New incoming connections
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
70 module:hook("s2s-stream-features", on_new_s2s, 10);
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
71
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
72 module:hook("s2s-authenticated", function(event)
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
73 local session = event.session;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
74 if session.posh and not session.secure then
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
75 -- Bogus replies should trigger this path
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
76 -- How does this interact with Dialback?
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
77 session:close({
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
78 condition = "policy-violation",
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
79 text = "Secure server-to-server communication is required but was not "
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
80 ..((session.direction == "outgoing" and "offered") or "used")
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
81 });
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
82 return false;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
83 end
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
84 -- Cleanup
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
85 session.posh = nil;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
86 end);
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
87 end
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
88
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
89 -- Do POSH authentication
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
90 module:hook("s2s-check-certificate", function(event)
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
91 local session, cert = event.session, event.cert;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
92 (session.log or module._log)("info", "Trying POSH authentication.");
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
93 -- if session.cert_identity_status ~= "valid" and session.posh then
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
94 if session.posh then
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
95 local target_host = event.host;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
96
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
97 local jwk = session.posh.jwk;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
98
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
99 local connection_certs = session.conn:socket():getpeerchain();
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
100
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
101 local x5c_table = jwk.keys[1].x5c;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
102
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
103 local wire_cert = connection_certs[1];
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
104 local jwk_cert = ssl.x509.load(der2pem(base64.decode(x5c_table[1])));
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
105
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
106 if (wire_cert and jwk_cert and
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
107 wire_cert:digest("sha1") == jwk_cert:digest("sha1")) then
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
108 session.cert_chain_status = "valid";
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
109 session.cert_identity_status = "valid";
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
110 (session.log or module._log)("debug", "POSH authentication succeeded!");
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
111 return true;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
112 else
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
113 (session.log or module._log)("debug", "POSH authentication failed!");
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
114 (session.log or module._log)("debug", "(top wire sha1 vs top jwk sha1) = (%s vs %s)", wire_cert:digest("sha1"), jwk_cert:digest("sha1"));
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
115 return false;
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
116 end
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
117 end
f3e452b43cfe mod_s2s_auth_posh: PKIX over Secure HTTP
Kim Alvefur <zash@zash.se>
parents:
diff changeset
118 end);