net/tls_luasec.lua
author Kim Alvefur <zash@zash.se>
Thu, 28 Mar 2024 15:26:57 +0100
changeset 13472 98806cac64c3
parent 13120 58e793288d9c
permissions -rw-r--r--
MUC: Switch to official XEP-0317 namespace for Hats (including compat) (thanks nicoco)
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
};