net/tls_luasec.lua
author Kim Alvefur <zash@zash.se>
Wed, 27 Mar 2024 19:33:11 +0100
changeset 13471 c2a476f4712a
parent 13120 58e793288d9c
permissions -rw-r--r--
util.startup: Fix exiting on pidfile trouble prosody.shutdown() relies on prosody.main_thread, which has not been set yet at this point. Doing a clean shutdown might actually be harmful in case it tears down things set up by the conflicting Prosody, such as the very pidfile we were looking at. Thanks again SigmaTel71 for noticing
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
12484
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
     1
-- Prosody IM
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
     2
-- Copyright (C) 2021 Prosody folks
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
     3
--
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
     4
-- This project is MIT/X11 licensed. Please see the
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
     5
-- COPYING file in the source package for more information.
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
     6
--
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
     7
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
     8
--[[
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
     9
This file provides a shim abstraction over LuaSec, consolidating some code
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    10
which was previously spread between net.server backends, portmanager and
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    11
certmanager.
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    12
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    13
The goal is to provide a more or less well-defined API on top of LuaSec which
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    14
abstracts away some of the things which are not needed and simplifies usage of
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    15
commonly used things (such as SNI contexts). Eventually, network backends
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    16
which do not rely on LuaSocket+LuaSec should be able to provide *this* API
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    17
instead of having to mimic LuaSec.
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    18
]]
12490
ee93df086926 net.tls_luasec: Harden dependency on LuaSec
Kim Alvefur <zash@zash.se>
parents: 12484
diff changeset
    19
local ssl = require "ssl";
12484
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    20
local ssl_newcontext = ssl.newcontext;
12490
ee93df086926 net.tls_luasec: Harden dependency on LuaSec
Kim Alvefur <zash@zash.se>
parents: 12484
diff changeset
    21
local ssl_context = ssl.context or require "ssl.context";
12484
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    22
local io_open = io.open;
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    23
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    24
local context_api = {};
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    25
local context_mt = {__index = context_api};
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    26
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    27
function context_api:set_sni_host(host, cert, key)
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    28
	local ctx, err = self._builder:clone():apply({
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    29
		certificate = cert,
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    30
		key = key,
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    31
	}):build();
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    32
	if not ctx then
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    33
		return false, err
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    34
	end
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    35
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    36
	self._sni_contexts[host] = ctx._inner
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    37
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    38
	return true, nil
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    39
end
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    40
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    41
function context_api:remove_sni_host(host)
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    42
	self._sni_contexts[host] = nil
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    43
end
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    44
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    45
function context_api:wrap(sock)
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    46
	local ok, conn, err = pcall(ssl.wrap, sock, self._inner);
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    47
	if not ok then
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    48
		return nil, err
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    49
	end
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    50
	return conn, nil
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    51
end
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    52
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    53
local function new_context(cfg, builder)
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    54
	-- LuaSec expects dhparam to be a callback that takes two arguments.
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    55
	-- We ignore those because it is mostly used for having a separate
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    56
	-- set of params for EXPORT ciphers, which we don't have by default.
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    57
	if type(cfg.dhparam) == "string" then
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    58
		local f, err = io_open(cfg.dhparam);
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    59
		if not f then return nil, "Could not open DH parameters: "..err end
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    60
		local dhparam = f:read("*a");
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    61
		f:close();
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    62
		cfg.dhparam = function() return dhparam; end
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    63
	end
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    64
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    65
	local inner, err = ssl_newcontext(cfg);
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    66
	if not inner then
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    67
		return nil, err
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    68
	end
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    69
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    70
	-- COMPAT Older LuaSec ignores the cipher list from the config, so we have to take care
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    71
	-- of it ourselves (W/A for #x)
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    72
	if inner and cfg.ciphers then
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    73
		local success;
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    74
		success, err = ssl_context.setcipher(inner, cfg.ciphers);
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    75
		if not success then
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    76
			return nil, err
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    77
		end
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    78
	end
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    79
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    80
	return setmetatable({
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    81
		_inner = inner,
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    82
		_builder = builder,
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    83
		_sni_contexts = {},
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    84
	}, context_mt), nil
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    85
end
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
    86
13119
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
    87
-- Feature detection / guessing
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
    88
local function test_option(option)
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
    89
	return not not ssl_newcontext({mode="server",protocol="sslv23",options={ option }});
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
    90
end
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
    91
local luasec_major, luasec_minor = ssl._VERSION:match("^(%d+)%.(%d+)");
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
    92
local luasec_version = tonumber(luasec_major) * 100 + tonumber(luasec_minor);
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
    93
local luasec_has = ssl.config or {
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
    94
	algorithms = {
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
    95
		ec = luasec_version >= 5;
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
    96
	};
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
    97
	capabilities = {
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
    98
		curves_list = luasec_version >= 7;
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
    99
	};
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
   100
	options = {
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
   101
		cipher_server_preference = test_option("cipher_server_preference");
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
   102
		no_ticket = test_option("no_ticket");
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
   103
		no_compression = test_option("no_compression");
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
   104
		single_dh_use = test_option("single_dh_use");
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
   105
		single_ecdh_use = test_option("single_ecdh_use");
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
   106
		no_renegotiation = test_option("no_renegotiation");
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
   107
	};
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
   108
};
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
   109
12484
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
   110
return {
13119
749376d75b40 net.certmanager: Move LuaSec feature detection to net.tls_luasec
Kim Alvefur <zash@zash.se>
parents: 12490
diff changeset
   111
	features = luasec_has;
12484
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
   112
	new_context = new_context,
13120
58e793288d9c net.tls_luasec: Expose method for loading a certificate
Kim Alvefur <zash@zash.se>
parents: 13119
diff changeset
   113
	load_certificate = ssl.loadcertificate;
12484
7e9ebdc75ce4 net: isolate LuaSec-specifics
Jonas Schäfer <jonas@wielicki.name>
parents:
diff changeset
   114
};