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