aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/server_epoll.lua35
-rw-r--r--net/server_event.lua28
-rw-r--r--net/server_select.lua18
-rw-r--r--net/tls_luasec.lua90
4 files changed, 156 insertions, 15 deletions
diff --git a/net/server_epoll.lua b/net/server_epoll.lua
index fa275d71..f8bab56c 100644
--- a/net/server_epoll.lua
+++ b/net/server_epoll.lua
@@ -18,7 +18,6 @@ local traceback = debug.traceback;
local logger = require "util.logger";
local log = logger.init("server_epoll");
local socket = require "socket";
-local luasec = require "ssl";
local realtime = require "util.time".now;
local monotonic = require "util.time".monotonic;
local indexedbheap = require "util.indexedbheap";
@@ -614,6 +613,30 @@ function interface:set_sslctx(sslctx)
self._sslctx = sslctx;
end
+function interface:sslctx()
+ return self.tls_ctx
+end
+
+function interface:ssl_info()
+ local sock = self.conn;
+ return sock.info and sock:info();
+end
+
+function interface:ssl_peercertificate()
+ local sock = self.conn;
+ return sock.getpeercertificate and sock:getpeercertificate();
+end
+
+function interface:ssl_peerverification()
+ local sock = self.conn;
+ return sock.getpeerverification and sock:getpeerverification();
+end
+
+function interface:ssl_peerfinished()
+ local sock = self.conn;
+ return sock.getpeerfinished and sock:getpeerfinished();
+end
+
function interface:starttls(tls_ctx)
if tls_ctx then self.tls_ctx = tls_ctx; end
self.starttls = false;
@@ -641,11 +664,7 @@ function interface:inittls(tls_ctx, now)
self.starttls = false;
self:debug("Starting TLS now");
self:updatenames(); -- Can't getpeer/sockname after wrap()
- local ok, conn, err = pcall(luasec.wrap, self.conn, self.tls_ctx);
- if not ok then
- conn, err = ok, conn;
- self:debug("Failed to initialize TLS: %s", err);
- end
+ local conn, err = self.tls_ctx:wrap(self.conn);
if not conn then
self:on("disconnect", err);
self:destroy();
@@ -656,8 +675,8 @@ function interface:inittls(tls_ctx, now)
if conn.sni then
if self.servername then
conn:sni(self.servername);
- elseif self._server and type(self._server.hosts) == "table" and next(self._server.hosts) ~= nil then
- conn:sni(self._server.hosts, true);
+ elseif next(self.tls_ctx._sni_contexts) ~= nil then
+ conn:sni(self.tls_ctx._sni_contexts, true);
end
end
if self.extra and self.extra.tlsa and conn.settlsa then
diff --git a/net/server_event.lua b/net/server_event.lua
index c30181b8..dfd94db4 100644
--- a/net/server_event.lua
+++ b/net/server_event.lua
@@ -47,7 +47,7 @@ local s_sub = string.sub
local coroutine_wrap = coroutine.wrap
local coroutine_yield = coroutine.yield
-local has_luasec, ssl = pcall ( require , "ssl" )
+local has_luasec = pcall ( require , "ssl" )
local socket = require "socket"
local levent = require "luaevent.core"
local inet = require "util.net";
@@ -153,7 +153,7 @@ function interface_mt:_start_ssl(call_onconnect) -- old socket will be destroyed
_ = self.eventwrite and self.eventwrite:close( )
self.eventread, self.eventwrite = nil, nil
local err
- self.conn, err = ssl.wrap( self.conn, self._sslctx )
+ self.conn, err = self._sslctx:wrap(self.conn)
if err then
self.fatalerror = err
self.conn = nil -- cannot be used anymore
@@ -168,8 +168,8 @@ function interface_mt:_start_ssl(call_onconnect) -- old socket will be destroyed
if self.conn.sni then
if self.servername then
self.conn:sni(self.servername);
- elseif self._server and type(self._server.hosts) == "table" and next(self._server.hosts) ~= nil then
- self.conn:sni(self._server.hosts, true);
+ elseif next(self._sslctx._sni_contexts) ~= nil then
+ self.conn:sni(self._sslctx._sni_contexts, true);
end
end
@@ -274,6 +274,26 @@ function interface_mt:pause()
return self:_lock(self.nointerface, true, self.nowriting);
end
+function interface_mt:sslctx()
+ return self._sslctx
+end
+
+function interface_mt:ssl_info()
+ return self.conn.info and self.conn:info()
+end
+
+function interface_mt:ssl_peercertificate()
+ return self.conn.getpeercertificate and self.conn:getpeercertificate()
+end
+
+function interface_mt:ssl_peerverification()
+ return self.conn.getpeerverification and self.conn:getpeerverification()
+end
+
+function interface_mt:ssl_peerfinished()
+ return self.conn.getpeerfinished and self.conn:getpeerfinished()
+end
+
function interface_mt:resume()
self:_lock(self.nointerface, false, self.nowriting);
if self.readcallback and not self.eventread then
diff --git a/net/server_select.lua b/net/server_select.lua
index eea850ce..51439fca 100644
--- a/net/server_select.lua
+++ b/net/server_select.lua
@@ -359,6 +359,18 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
handler.sslctx = function ( )
return sslctx
end
+ handler.ssl_info = function( )
+ return socket.info and socket:info()
+ end
+ handler.ssl_peercertificate = function( )
+ return socket.getpeercertificate and socket:getpeercertificate()
+ end
+ handler.ssl_peerverification = function( )
+ return socket.getpeerverification and socket:getpeerverification()
+ end
+ handler.ssl_peerfinished = function( )
+ return socket.getpeerfinished and socket:getpeerfinished()
+ end
handler.send = function( _, data, i, j )
return send( socket, data, i, j )
end
@@ -652,7 +664,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
end
out_put( "server.lua: attempting to start tls on " .. tostring( socket ) )
local oldsocket, err = socket
- socket, err = ssl_wrap( socket, sslctx ) -- wrap socket
+ socket, err = sslctx:wrap(socket) -- wrap socket
if not socket then
out_put( "server.lua: error while starting tls on client: ", tostring(err or "unknown error") )
@@ -662,8 +674,8 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
if socket.sni then
if self.servername then
socket:sni(self.servername);
- elseif self._server and type(self._server.hosts) == "table" and next(self._server.hosts) ~= nil then
- socket:sni(self.server().hosts, true);
+ elseif next(sslctx._sni_contexts) ~= nil then
+ socket:sni(sslctx._sni_contexts, true);
end
end
diff --git a/net/tls_luasec.lua b/net/tls_luasec.lua
new file mode 100644
index 00000000..680b455e
--- /dev/null
+++ b/net/tls_luasec.lua
@@ -0,0 +1,90 @@
+-- Prosody IM
+-- Copyright (C) 2021 Prosody folks
+--
+-- This project is MIT/X11 licensed. Please see the
+-- COPYING file in the source package for more information.
+--
+
+--[[
+This file provides a shim abstraction over LuaSec, consolidating some code
+which was previously spread between net.server backends, portmanager and
+certmanager.
+
+The goal is to provide a more or less well-defined API on top of LuaSec which
+abstracts away some of the things which are not needed and simplifies usage of
+commonly used things (such as SNI contexts). Eventually, network backends
+which do not rely on LuaSocket+LuaSec should be able to provide *this* API
+instead of having to mimic LuaSec.
+]]
+local softreq = require"util.dependencies".softreq;
+local ssl = softreq"ssl";
+local ssl_newcontext = ssl.newcontext;
+local ssl_context = ssl.context or softreq"ssl.context";
+local io_open = io.open;
+
+local context_api = {};
+local context_mt = {__index = context_api};
+
+function context_api:set_sni_host(host, cert, key)
+ local ctx, err = self._builder:clone():apply({
+ certificate = cert,
+ key = key,
+ }):build();
+ if not ctx then
+ return false, err
+ end
+
+ self._sni_contexts[host] = ctx._inner
+
+ return true, nil
+end
+
+function context_api:remove_sni_host(host)
+ self._sni_contexts[host] = nil
+end
+
+function context_api:wrap(sock)
+ local ok, conn, err = pcall(ssl.wrap, sock, self._inner);
+ if not ok then
+ return nil, err
+ end
+ return conn, nil
+end
+
+local function new_context(cfg, builder)
+ -- LuaSec expects dhparam to be a callback that takes two arguments.
+ -- We ignore those because it is mostly used for having a separate
+ -- set of params for EXPORT ciphers, which we don't have by default.
+ if type(cfg.dhparam) == "string" then
+ local f, err = io_open(cfg.dhparam);
+ if not f then return nil, "Could not open DH parameters: "..err end
+ local dhparam = f:read("*a");
+ f:close();
+ cfg.dhparam = function() return dhparam; end
+ end
+
+ local inner, err = ssl_newcontext(cfg);
+ if not inner then
+ return nil, err
+ end
+
+ -- COMPAT Older LuaSec ignores the cipher list from the config, so we have to take care
+ -- of it ourselves (W/A for #x)
+ if inner and cfg.ciphers then
+ local success;
+ success, err = ssl_context.setcipher(inner, cfg.ciphers);
+ if not success then
+ return nil, err
+ end
+ end
+
+ return setmetatable({
+ _inner = inner,
+ _builder = builder,
+ _sni_contexts = {},
+ }, context_mt), nil
+end
+
+return {
+ new_context = new_context,
+};