|
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 }; |