Software /
code /
prosody
Comparison
plugins/mod_saslauth.lua @ 13278:aa17086a9c8a
mod_saslauth: Derive hash from certificate per tls-server-end-point
This originally used a WIP implementation of cert:sigalg(), a method to
retrieve certificate signature algorithm, but it was never submitted
upstream. https://github.com/Zash/luasec/tree/zash/sigalg
cert:getsignaturename() was merged in
https://github.com/brunoos/luasec/commit/de393417b7c7566caf1e0a0ad54132942ac4f049
XEP-0440 v0.3.0 made implementing tls-server-end-point a MUST
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Tue, 29 Jun 2021 00:22:36 +0200 |
parent | 13277:0b4c3573b248 |
child | 13281:288ddca37639 |
comparison
equal
deleted
inserted
replaced
13277:0b4c3573b248 | 13278:aa17086a9c8a |
---|---|
13 local sm_make_authenticated = require "prosody.core.sessionmanager".make_authenticated; | 13 local sm_make_authenticated = require "prosody.core.sessionmanager".make_authenticated; |
14 local base64 = require "prosody.util.encodings".base64; | 14 local base64 = require "prosody.util.encodings".base64; |
15 local set = require "prosody.util.set"; | 15 local set = require "prosody.util.set"; |
16 local errors = require "prosody.util.error"; | 16 local errors = require "prosody.util.error"; |
17 local hex = require "prosody.util.hex"; | 17 local hex = require "prosody.util.hex"; |
18 local pem2der = require"util.x509".pem2der; | |
19 local hashes = require"util.hashes"; | |
20 local ssl = require "ssl"; -- FIXME Isolate LuaSec from the rest of the code | |
18 | 21 |
19 local usermanager_get_sasl_handler = require "prosody.core.usermanager".get_sasl_handler; | 22 local usermanager_get_sasl_handler = require "prosody.core.usermanager".get_sasl_handler; |
20 | 23 |
21 local secure_auth_only = module:get_option_boolean("c2s_require_encryption", module:get_option_boolean("require_encryption", true)); | 24 local secure_auth_only = module:get_option_boolean("c2s_require_encryption", module:get_option_boolean("require_encryption", true)); |
22 local allow_unencrypted_plain_auth = module:get_option_boolean("allow_unencrypted_plain_auth", false) | 25 local allow_unencrypted_plain_auth = module:get_option_boolean("allow_unencrypted_plain_auth", false) |
258 end | 261 end |
259 | 262 |
260 local function tls_server_end_point(self) | 263 local function tls_server_end_point(self) |
261 local cert_hash = self.userdata["tls-server-end-point"]; | 264 local cert_hash = self.userdata["tls-server-end-point"]; |
262 if cert_hash then return hex.from(cert_hash); end | 265 if cert_hash then return hex.from(cert_hash); end |
266 | |
267 -- Hash function selection, see RFC 5929 §4.1 | |
268 local certfile = self.userdata["tls-server-end-point-cert"]; | |
269 if not certfile then return end | |
270 local f = io.open(certfile); | |
271 if not f then return end | |
272 local hash = hashes.sha256; | |
273 | |
274 -- FIXME TOCTOU | |
275 -- We don't know that this is the right cert, it could have been replaced on | |
276 -- disk since we started. Best would be if we could extract the cert used | |
277 -- from the SSL context. | |
278 local certdata = f:read("*"); | |
279 local cert = ssl.loadcertificate(certdata); | |
280 | |
281 if cert.getsignaturename then | |
282 local sigalg = cert:getsignaturename():lower():match("sha%d+"); | |
283 if sigalg and sigalg ~= "sha1" and hashes[sigalg] then | |
284 -- This should have ruled out MD5 and SHA1 | |
285 hash = hashes[sigalg]; | |
286 end | |
287 end | |
288 | |
289 return hash(pem2der(cert)); | |
263 end | 290 end |
264 | 291 |
265 local mechanisms_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-sasl' }; | 292 local mechanisms_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-sasl' }; |
266 local bind_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-bind' }; | 293 local bind_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-bind' }; |
267 local xmpp_session_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-session' }; | 294 local xmpp_session_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-session' }; |
293 sasl_handler:add_cb_handler("tls-unique", tls_unique); | 320 sasl_handler:add_cb_handler("tls-unique", tls_unique); |
294 channel_bindings:add("tls-unique"); | 321 channel_bindings:add("tls-unique"); |
295 else | 322 else |
296 log("debug", "Channel binding 'tls-unique' not supported (by LuaSec?)"); | 323 log("debug", "Channel binding 'tls-unique' not supported (by LuaSec?)"); |
297 end | 324 end |
325 local certfile = origin.ssl_cfg and origin.ssl_cfg.certificate; | |
326 -- FIXME .ssl_cfg is set by mod_tls and thus only available with starttls | |
298 if tls_server_end_point_hash then | 327 if tls_server_end_point_hash then |
299 log("debug", "Channel binding 'tls-server-end-point' can be offered with the configured certificate hash"); | 328 log("debug", "Channel binding 'tls-server-end-point' can be offered with the configured certificate hash"); |
329 sasl_handler:add_cb_handler("tls-server-end-point", tls_server_end_point); | |
330 channel_bindings:add("tls-server-end-point"); | |
331 elseif certfile then | |
332 log("debug", "Channel binding 'tls-server-end-point' can be offered based on the certificate used"); | |
300 sasl_handler:add_cb_handler("tls-server-end-point", tls_server_end_point); | 333 sasl_handler:add_cb_handler("tls-server-end-point", tls_server_end_point); |
301 channel_bindings:add("tls-server-end-point"); | 334 channel_bindings:add("tls-server-end-point"); |
302 end | 335 end |
303 sasl_handler["userdata"] = { | 336 sasl_handler["userdata"] = { |
304 ["tls-unique"] = origin.conn; | 337 ["tls-unique"] = origin.conn; |
305 ["tls-exporter"] = origin.conn; | 338 ["tls-exporter"] = origin.conn; |
339 ["tls-server-end-point-cert"] = certfile; | |
306 ["tls-server-end-point"] = tls_server_end_point_hash; | 340 ["tls-server-end-point"] = tls_server_end_point_hash; |
307 }; | 341 }; |
308 else | 342 else |
309 log("debug", "Channel binding not supported by SASL handler"); | 343 log("debug", "Channel binding not supported by SASL handler"); |
310 end | 344 end |