From ab40a27df16e912e23812e2d75e52c7f083b81d8 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sun, 5 Oct 2008 17:33:38 +0100 Subject: TLS: Handshake works, no data after that --- core/modulemanager.lua | 1 + main.lua | 4 +- net/server.lua | 222 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 220 insertions(+), 7 deletions(-) diff --git a/core/modulemanager.lua b/core/modulemanager.lua index 696e0f08..1ad1f990 100644 --- a/core/modulemanager.lua +++ b/core/modulemanager.lua @@ -49,6 +49,7 @@ function loadall() load("legacyauth"); load("roster"); load("register"); + load("tls"); end function load(name) diff --git a/main.lua b/main.lua index 821b3273..633c3df8 100644 --- a/main.lua +++ b/main.lua @@ -101,7 +101,7 @@ setmetatable(_G, { __index = function (t, k) print("WARNING: ATTEMPT TO READ A N local protected_handler = function (conn, data, err) local success, ret = pcall(handler, conn, data, err); if not success then print("ERROR on "..tostring(conn)..": "..ret); conn:close(); end end; local protected_disconnect = function (conn, err) local success, ret = pcall(disconnect, conn, err); if not success then print("ERROR on "..tostring(conn).." disconnect: "..ret); conn:close(); end end; -server.add( { listener = protected_handler, disconnect = protected_disconnect }, 5222, "*", 1, nil ) -- server.add will send a status message -server.add( { listener = protected_handler, disconnect = protected_disconnect }, 5223, "*", 1, ssl_ctx ) -- server.add will send a status message +server.add( { listener = protected_handler, disconnect = protected_disconnect }, 5222, "*", 1, ssl_ctx ) -- server.add will send a status message +--server.add( { listener = protected_handler, disconnect = protected_disconnect }, 5223, "*", 1, ssl_ctx ) -- server.add will send a status message server.loop(); diff --git a/net/server.lua b/net/server.lua index 8849289c..2cbfa3a2 100644 --- a/net/server.lua +++ b/net/server.lua @@ -39,6 +39,7 @@ local coroutine_wrap = coroutine.wrap local coroutine_yield = coroutine.yield local print = print; local out_put = function () end --print; +local out_put = print; local out_error = print; --// extern libs //-- @@ -105,8 +106,6 @@ wrapserver = function( listener, socket, ip, serverport, mode, sslctx ) -- th if sslctx then if not ssl_newcontext then return nil, "luasec not found" --- elseif not cfg_get "use_ssl" then --- return nil, "ssl is deactivated" end if type( sslctx ) ~= "table" then out_error "server.lua: wrong server sslctx" @@ -119,6 +118,7 @@ wrapserver = function( listener, socket, ip, serverport, mode, sslctx ) -- th return nil, err end wrapclient = wrapsslclient + wrapclient = wraptlsclient else wrapclient = wraptcpclient end @@ -356,6 +356,216 @@ wrapsslclient = function( listener, socket, ip, serverport, clientport, mode, ss return handler, socket end +wraptlsclient = function( listener, socket, ip, serverport, clientport, mode, sslctx ) -- this function wraps a tls cleint + + local dispatch, disconnect = listener.listener, listener.disconnect + + --// transform socket to ssl object //-- + + local err + + socket:settimeout( 0 ) + + --// private closures of the object //-- + + local writequeue = { } -- buffer for messages to send + + local eol -- end of buffer + + local sstat, rstat = 0, 0 + + --// local import of socket methods //-- + + local send = socket.send + local receive = socket.receive + local close = socket.close + --local shutdown = socket.shutdown + + --// public methods of the object //-- + + local handler = { } + + handler.getstats = function( ) + return rstat, sstat + end + + handler.listener = function( data, err ) + return listener( handler, data, err ) + end + handler.ssl = function( ) + return false + end + handler.send = function( _, data, i, j ) + return send( socket, data, i, j ) + end + handler.receive = function( pattern, prefix ) + return receive( socket, pattern, prefix ) + end + handler.shutdown = function( pattern ) + --return shutdown( socket, pattern ) + end + handler.close = function( closed ) + close( socket ) + writelen = ( eol and removesocket( writelist, socket, writelen ) ) or writelen + readlen = removesocket( readlist, socket, readlen ) + socketlist[ socket ] = nil + out_put "server.lua: closed handler and removed socket from list" + end + handler.ip = function( ) + return ip + end + handler.serverport = function( ) + return serverport + end + handler.clientport = function( ) + return clientport + end + + handler.write = function( data ) + if not eol then + writelen = writelen + 1 + writelist[ writelen ] = socket + eol = 0 + end + eol = eol + 1 + writequeue[ eol ] = data + end + handler.writequeue = function( ) + return writequeue + end + handler.socket = function( ) + return socket + end + handler.mode = function( ) + return mode + end + handler._receivedata = function( ) + local data, err, part = receive( socket, mode ) -- receive data in "mode" + if not err or ( err == "timeout" or err == "wantread" ) then -- received something + local data = data or part or "" + local count = #data * STAT_UNIT + rstat = rstat + count + receivestat = receivestat + count + out_put( "server.lua: read data '", data, "', error: ", err ) + return dispatch( handler, data, err ) + else -- connections was closed or fatal error + out_put( "server.lua: client ", ip, ":", clientport, " error: ", err ) + handler.close( ) + disconnect( handler, err ) + writequeue = nil + handler = nil + return false + end + end + handler._dispatchdata = function( ) -- this function writes data to handlers + local buffer = table_concat( writequeue, "", 1, eol ) + local succ, err, byte = send( socket, buffer ) + local count = ( succ or 0 ) * STAT_UNIT + sstat = sstat + count + sendstat = sendstat + count + out_put( "server.lua: sended '", buffer, "', bytes: ", succ, ", error: ", err, ", part: ", byte, ", to: ", ip, ":", clientport ) + if succ then -- sending succesful + --writequeue = { } + eol = nil + writelen = removesocket( writelist, socket, writelen ) -- delete socket from writelist + if handler.need_tls then + out_put("server.lua: connection is ready for tls handshake"); + handler.need_tls = not handler.starttls(true); + end + return true + elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write + buffer = string_sub( buffer, byte + 1, -1 ) -- new buffer + writequeue[ 1 ] = buffer -- insert new buffer in queue + eol = 1 + return true + else -- connection was closed during sending or fatal error + out_put( "server.lua: client ", ip, ":", clientport, " error: ", err ) + handler.close( ) + disconnect( handler, err ) + writequeue = nil + handler = nil + return false + end + end + + handler.receivedata, handler.dispatchdata = handler._receivedata, handler._dispatchdata; + -- // COMPAT // -- + + handler.getIp = handler.ip + handler.getPort = handler.clientport + + --// handshake //-- + + local wrote, read + + handler.starttls = function (now) + if not now then handler.need_tls = true; return; end + out_put( "server.lua: attempting to start tls on "..tostring(socket) ) + socket, err = ssl_wrap( socket, sslctx ) -- wrap socket + out_put("sslwrapped socket is "..tostring(socket)); + if err then + out_put( "server.lua: ssl error: ", err ) + return nil, nil, err -- fatal error + end + socket:settimeout( 1 ) + send = socket.send + receive = socket.receive + close = socket.close + print(readlen, writelen) + for _, s in ipairs(readlist) do print("R:", tostring(s)) end + for _, s in ipairs(writelist) do print("W:", tostring(s)) end + handler.ssl = function( ) + return true + end + handler.send = function( _, data, i, j ) + return send( socket, data, i, j ) + end + handler.receive = function( pattern, prefix ) + return receive( socket, pattern, prefix ) + end + + handler.handshake = function (conn) + local succ, msg + out_put("ssl handshaking on socket "..tostring(conn)) + conn:settimeout() + while not succ do + succ, msg = conn:dohandshake() + out_put("msg: "..tostring(msg)) + if msg == 'wantread' then + socket_select({conn}, nil) + elseif msg == 'wantwrite' then + socket_select(nil, {conn}) + elseif not succ then + -- other error + _ = err ~= "closed" and close( socket ) + handler.close( ) + disconnect( handler, err ) + writequeue = nil + handler = nil + out_error("server.lua: ssl handshake failed"); + return false -- handshake failed + end + + end + out_put("server.lua: ssl handshake succeeded!"); + handler.receivedata = handler._receivedata; + handler.dispatchdata = handler._dispatchdata; + return true; + end + + handler.receivedata = handler.handshake + handler.dispatchdata = handler.handshake + + return handler.handshake( socket ) -- do handshake + end + + socketlist[ socket ] = handler + readlen = readlen + 1 + readlist[ readlen ] = socket + + return handler, socket +end + wraptcpclient = function( listener, socket, ip, serverport, clientport, mode ) -- this function wraps a socket local dispatch, disconnect = listener.listener, listener.disconnect @@ -433,6 +643,7 @@ wraptcpclient = function( listener, socket, ip, serverport, clientport, mode ) handler.mode = function( ) return mode end + handler.receivedata = function( ) local data, err, part = receive( socket, mode ) -- receive data in "mode" if not err or ( err == "timeout" or err == "wantread" ) then -- received something @@ -451,6 +662,7 @@ wraptcpclient = function( listener, socket, ip, serverport, clientport, mode ) return false end end + handler.dispatchdata = function( ) -- this function writes data to handlers local buffer = table_concat( writequeue, "", 1, eol ) local succ, err, byte = send( socket, buffer ) @@ -573,6 +785,7 @@ end loop = function( ) -- this is the main loop of the program --signal_set( "hub", "run" ) repeat + out_put("select()") local read, write, err = socket_select( readlist, writelist, 1 ) -- 1 sec timeout, nice for timers for i, socket in ipairs( write ) do -- send data waiting in writequeues local handler = socketlist[ socket ] @@ -593,9 +806,8 @@ loop = function( ) -- this is the main loop of the program end end firetimer( ) - --collectgarbage "collect" - until false --signal_get "hub" ~= "run" - return --signal_get "hub" + until false + return end ----------------------------------// BEGIN //-- -- cgit v1.2.3 From 0c9336110d8dceb2c9801ee68b9817801014fefe Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sun, 5 Oct 2008 19:10:21 +0100 Subject: Working TLS! --- core/stanza_router.lua | 1 + net/server.lua | 85 +++++++++++++++++++++++++++----------------------- 2 files changed, 47 insertions(+), 39 deletions(-) diff --git a/core/stanza_router.lua b/core/stanza_router.lua index 89bea131..489bb96d 100644 --- a/core/stanza_router.lua +++ b/core/stanza_router.lua @@ -11,6 +11,7 @@ require "util.jid" local jid_split = jid.split; function core_process_stanza(origin, stanza) + log("debug", "Received: "..tostring(stanza)) local to = stanza.attr.to; if not to or (hosts[to] and hosts[to].type == "local") then diff --git a/net/server.lua b/net/server.lua index 2cbfa3a2..1edbe7b7 100644 --- a/net/server.lua +++ b/net/server.lua @@ -446,7 +446,7 @@ wraptlsclient = function( listener, socket, ip, serverport, clientport, mode, ss local count = #data * STAT_UNIT rstat = rstat + count receivestat = receivestat + count - out_put( "server.lua: read data '", data, "', error: ", err ) + --out_put( "server.lua: read data '", data, "', error: ", err ) return dispatch( handler, data, err ) else -- connections was closed or fatal error out_put( "server.lua: client ", ip, ":", clientport, " error: ", err ) @@ -470,7 +470,10 @@ wraptlsclient = function( listener, socket, ip, serverport, clientport, mode, ss writelen = removesocket( writelist, socket, writelen ) -- delete socket from writelist if handler.need_tls then out_put("server.lua: connection is ready for tls handshake"); - handler.need_tls = not handler.starttls(true); + handler.starttls(true); + if handler.need_tls then + out_put("server.lua: uh-oh... we still want tls, something must be wrong"); + end end return true elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write @@ -499,7 +502,7 @@ wraptlsclient = function( listener, socket, ip, serverport, clientport, mode, ss local wrote, read handler.starttls = function (now) - if not now then handler.need_tls = true; return; end + if not now then out_put("server.lua: we need to do tls, but delaying until later"); handler.need_tls = true; return; end out_put( "server.lua: attempting to start tls on "..tostring(socket) ) socket, err = ssl_wrap( socket, sslctx ) -- wrap socket out_put("sslwrapped socket is "..tostring(socket)); @@ -511,9 +514,6 @@ wraptlsclient = function( listener, socket, ip, serverport, clientport, mode, ss send = socket.send receive = socket.receive close = socket.close - print(readlen, writelen) - for _, s in ipairs(readlist) do print("R:", tostring(s)) end - for _, s in ipairs(writelist) do print("W:", tostring(s)) end handler.ssl = function( ) return true end @@ -523,42 +523,46 @@ wraptlsclient = function( listener, socket, ip, serverport, clientport, mode, ss handler.receive = function( pattern, prefix ) return receive( socket, pattern, prefix ) end - - handler.handshake = function (conn) - local succ, msg - out_put("ssl handshaking on socket "..tostring(conn)) - conn:settimeout() - while not succ do - succ, msg = conn:dohandshake() - out_put("msg: "..tostring(msg)) - if msg == 'wantread' then - socket_select({conn}, nil) - elseif msg == 'wantwrite' then - socket_select(nil, {conn}) - elseif not succ then - -- other error - _ = err ~= "closed" and close( socket ) - handler.close( ) - disconnect( handler, err ) - writequeue = nil - handler = nil - out_error("server.lua: ssl handshake failed"); - return false -- handshake failed + + handler.handshake = coroutine_wrap( function( client ) + local err + for i = 1, 10 do -- 10 handshake attemps + _, err = client:dohandshake( ) + if not err then + out_put( "server.lua: ssl handshake done" ) + writelen = ( wrote and removesocket( writelist, socket, writelen ) ) or writelen + handler.receivedata = handler._receivedata -- when handshake is done, replace the handshake function with regular functions + handler.dispatchdata = handler._dispatchdata + handler.need_tls = nil + socketlist[ client ] = handler + readlen = readlen + 1 + readlist[ readlen ] = client + return true; + else + out_put( "server.lua: error during ssl handshake: ", err ) + if err == "wantwrite" then + if wrote == nil then + writelen = writelen + 1 + writelist[ writelen ] = client + wrote = true end - end - out_put("server.lua: ssl handshake succeeded!"); - handler.receivedata = handler._receivedata; - handler.dispatchdata = handler._dispatchdata; - return true; + coroutine_yield( handler, nil, err ) -- handshake not finished end - - handler.receivedata = handler.handshake - handler.dispatchdata = handler.handshake + end + _ = err ~= "closed" and close( socket ) + handler.close( ) + disconnect( handler, err ) + writequeue = nil + handler = nil + return false -- handshake failed + end + ) + handler.receivedata = handler.handshake + handler.dispatchdata = handler.handshake - return handler.handshake( socket ) -- do handshake - end - + handler.handshake( socket ) -- do handshake + end socketlist[ socket ] = handler readlen = readlen + 1 readlist[ readlen ] = socket @@ -785,7 +789,10 @@ end loop = function( ) -- this is the main loop of the program --signal_set( "hub", "run" ) repeat - out_put("select()") + --[[print(readlen, writelen) + for _, s in ipairs(readlist) do print("R:", tostring(s)) end + for _, s in ipairs(writelist) do print("W:", tostring(s)) end + out_put("select()"..os.time())]] local read, write, err = socket_select( readlist, writelist, 1 ) -- 1 sec timeout, nice for timers for i, socket in ipairs( write ) do -- send data waiting in writequeues local handler = socketlist[ socket ] -- cgit v1.2.3