Software /
code /
prosody-modules
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 |
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); |