You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
3.0 KiB
Lua
116 lines
3.0 KiB
Lua
3 years ago
|
--[[
|
||
|
|
||
|
Copyright 2016 The Luvit Authors. All Rights Reserved.
|
||
|
|
||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
you may not use this file except in compliance with the License.
|
||
|
You may obtain a copy of the License at
|
||
|
|
||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
Unless required by applicable law or agreed to in writing, software
|
||
|
distributed under the License is distributed on an "AS-IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
See the License for the specific language governing permissions and
|
||
|
limitations under the License.
|
||
|
|
||
|
--]]
|
||
|
local openssl = require('openssl')
|
||
|
|
||
|
-- writeCipher is called when ssl needs something written on the socket
|
||
|
-- handshakeComplete is called when the handhake is complete and it's safe
|
||
|
-- onPlain is called when plaintext comes out.
|
||
|
return function (ctx, isServer, socket, handshakeComplete, servername)
|
||
|
|
||
|
local bin, bout = openssl.bio.mem(8192), openssl.bio.mem(8192)
|
||
|
local ssl = ctx:ssl(bin, bout, isServer)
|
||
|
|
||
|
if not isServer and servername then
|
||
|
ssl:set('hostname', servername)
|
||
|
end
|
||
|
|
||
|
local ssocket = {tls=true}
|
||
|
local onPlain
|
||
|
|
||
|
local function flush(callback)
|
||
|
local chunks = {}
|
||
|
local i = 0
|
||
|
while bout:pending() > 0 do
|
||
|
i = i + 1
|
||
|
chunks[i] = bout:read()
|
||
|
end
|
||
|
if i == 0 then
|
||
|
if callback then callback() end
|
||
|
return true
|
||
|
end
|
||
|
return socket:write(chunks, callback)
|
||
|
end
|
||
|
|
||
|
local function handshake(callback)
|
||
|
if ssl:handshake() then
|
||
|
local success, result = ssl:getpeerverification()
|
||
|
socket:read_stop()
|
||
|
if not success and result then
|
||
|
handshakeComplete("Error verifying peer: " .. result[1].error_string)
|
||
|
end
|
||
|
handshakeComplete(nil, ssocket)
|
||
|
end
|
||
|
return flush(callback)
|
||
|
end
|
||
|
|
||
|
local function onCipher(err, data)
|
||
|
if not onPlain then
|
||
|
if err or not data then
|
||
|
return handshakeComplete(err or "Peer aborted the SSL handshake", data)
|
||
|
end
|
||
|
bin:write(data)
|
||
|
return handshake()
|
||
|
end
|
||
|
if err or not data then
|
||
|
return onPlain(err, data)
|
||
|
end
|
||
|
bin:write(data)
|
||
|
while true do
|
||
|
local plain = ssl:read()
|
||
|
if not plain then break end
|
||
|
onPlain(nil, plain)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- When requested to start reading, start the real socket and setup
|
||
|
-- onPlain handler
|
||
|
function ssocket.read_start(_, onRead)
|
||
|
onPlain = onRead
|
||
|
return socket:read_start(onCipher)
|
||
|
end
|
||
|
|
||
|
-- When requested to write plain data, encrypt it and write to socket
|
||
|
function ssocket.write(_, plain, callback)
|
||
|
ssl:write(plain)
|
||
|
return flush(callback)
|
||
|
end
|
||
|
|
||
|
function ssocket.shutdown(_, ...)
|
||
|
return socket:shutdown(...)
|
||
|
end
|
||
|
function ssocket.read_stop(_, ...)
|
||
|
return socket:read_stop(...)
|
||
|
end
|
||
|
function ssocket.is_closing(_, ...)
|
||
|
return socket:is_closing(...)
|
||
|
end
|
||
|
function ssocket.close(_, ...)
|
||
|
return socket:close(...)
|
||
|
end
|
||
|
function ssocket.unref(_, ...)
|
||
|
return socket:unref(...)
|
||
|
end
|
||
|
function ssocket.ref(_, ...)
|
||
|
return socket:ref(...)
|
||
|
end
|
||
|
|
||
|
handshake()
|
||
|
socket:read_start(onCipher)
|
||
|
|
||
|
end
|