net/tls_luasec.lua
changeset 12484 7e9ebdc75ce4
child 12490 ee93df086926
equal deleted inserted replaced
12482:82270a6b1234 12484:7e9ebdc75ce4
       
     1 -- Prosody IM
       
     2 -- Copyright (C) 2021 Prosody folks
       
     3 --
       
     4 -- This project is MIT/X11 licensed. Please see the
       
     5 -- COPYING file in the source package for more information.
       
     6 --
       
     7 
       
     8 --[[
       
     9 This file provides a shim abstraction over LuaSec, consolidating some code
       
    10 which was previously spread between net.server backends, portmanager and
       
    11 certmanager.
       
    12 
       
    13 The goal is to provide a more or less well-defined API on top of LuaSec which
       
    14 abstracts away some of the things which are not needed and simplifies usage of
       
    15 commonly used things (such as SNI contexts). Eventually, network backends
       
    16 which do not rely on LuaSocket+LuaSec should be able to provide *this* API
       
    17 instead of having to mimic LuaSec.
       
    18 ]]
       
    19 local softreq = require"util.dependencies".softreq;
       
    20 local ssl = softreq"ssl";
       
    21 local ssl_newcontext = ssl.newcontext;
       
    22 local ssl_context = ssl.context or softreq"ssl.context";
       
    23 local io_open = io.open;
       
    24 
       
    25 local context_api = {};
       
    26 local context_mt = {__index = context_api};
       
    27 
       
    28 function context_api:set_sni_host(host, cert, key)
       
    29 	local ctx, err = self._builder:clone():apply({
       
    30 		certificate = cert,
       
    31 		key = key,
       
    32 	}):build();
       
    33 	if not ctx then
       
    34 		return false, err
       
    35 	end
       
    36 
       
    37 	self._sni_contexts[host] = ctx._inner
       
    38 
       
    39 	return true, nil
       
    40 end
       
    41 
       
    42 function context_api:remove_sni_host(host)
       
    43 	self._sni_contexts[host] = nil
       
    44 end
       
    45 
       
    46 function context_api:wrap(sock)
       
    47 	local ok, conn, err = pcall(ssl.wrap, sock, self._inner);
       
    48 	if not ok then
       
    49 		return nil, err
       
    50 	end
       
    51 	return conn, nil
       
    52 end
       
    53 
       
    54 local function new_context(cfg, builder)
       
    55 	-- LuaSec expects dhparam to be a callback that takes two arguments.
       
    56 	-- We ignore those because it is mostly used for having a separate
       
    57 	-- set of params for EXPORT ciphers, which we don't have by default.
       
    58 	if type(cfg.dhparam) == "string" then
       
    59 		local f, err = io_open(cfg.dhparam);
       
    60 		if not f then return nil, "Could not open DH parameters: "..err end
       
    61 		local dhparam = f:read("*a");
       
    62 		f:close();
       
    63 		cfg.dhparam = function() return dhparam; end
       
    64 	end
       
    65 
       
    66 	local inner, err = ssl_newcontext(cfg);
       
    67 	if not inner then
       
    68 		return nil, err
       
    69 	end
       
    70 
       
    71 	-- COMPAT Older LuaSec ignores the cipher list from the config, so we have to take care
       
    72 	-- of it ourselves (W/A for #x)
       
    73 	if inner and cfg.ciphers then
       
    74 		local success;
       
    75 		success, err = ssl_context.setcipher(inner, cfg.ciphers);
       
    76 		if not success then
       
    77 			return nil, err
       
    78 		end
       
    79 	end
       
    80 
       
    81 	return setmetatable({
       
    82 		_inner = inner,
       
    83 		_builder = builder,
       
    84 		_sni_contexts = {},
       
    85 	}, context_mt), nil
       
    86 end
       
    87 
       
    88 return {
       
    89 	new_context = new_context,
       
    90 };