Comparison

net/tls_luasec.lua @ 12480:7e9ebdc75ce4

net: isolate LuaSec-specifics For this, various accessor functions are now provided directly on the sockets, which reach down into the LuaSec implementation to obtain the information. While this may seem of little gain at first, it hides the implementation detail of the LuaSec+LuaSocket combination that the actual socket and the TLS layer are separate objects. The net gain here is that an alternative implementation does not have to emulate that specific implementation detail and "only" has to expose LuaSec-compatible data structures on the new functions.
author Jonas Schäfer <jonas@wielicki.name>
date Wed, 27 Apr 2022 17:44:14 +0200
child 12486:ee93df086926
comparison
equal deleted inserted replaced
12478:82270a6b1234 12480: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 };