This commit is contained in:
Benjamin Kyd
2019-04-09 20:55:44 +01:00
parent 7dce6cab72
commit 6761ddab08
93 changed files with 14575 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
--[[
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

View File

@@ -0,0 +1,121 @@
--[[
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')
local loadResource
if type(module) == "table" then
function loadResource(path)
return module:load(path)
end
else
loadResource = require('resource').load
end
local bit = require('bit')
local DEFAULT_SECUREPROTOCOL
do
local _, _, V = openssl.version()
local isLibreSSL = V:find('^LibreSSL')
_, _, V = openssl.version(true)
local isTLSv1_3 = not isLibreSSL and V > 0x10100000
if isTLSv1_3 then
DEFAULT_SECUREPROTOCOL = 'TLS'
else
DEFAULT_SECUREPROTOCOL = 'SSLv23'
end
end
local DEFAULT_CIPHERS = 'TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256:' .. --TLS 1.3
'ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:' .. --TLS 1.2
'RC4:HIGH:!MD5:!aNULL:!EDH' --TLS 1.0
local DEFAULT_CA_STORE
do
local data = assert(loadResource("./root_ca.dat"))
DEFAULT_CA_STORE = openssl.x509.store:new()
local index = 1
local dataLength = #data
while index < dataLength do
local len = bit.bor(bit.lshift(data:byte(index), 8), data:byte(index + 1))
index = index + 2
local cert = assert(openssl.x509.read(data:sub(index, index + len)))
index = index + len
assert(DEFAULT_CA_STORE:add(cert))
end
end
local function returnOne()
return 1
end
return function (options)
local ctx = openssl.ssl.ctx_new(
options.protocol or DEFAULT_SECUREPROTOCOL,
options.ciphers or DEFAULT_CIPHERS)
local key, cert, ca
if options.key then
key = assert(openssl.pkey.read(options.key, true, 'pem'))
end
if options.cert then
cert = {}
for chunk in options.cert:gmatch("%-+BEGIN[^-]+%-+[^-]+%-+END[^-]+%-+") do
cert[#cert + 1] = assert(openssl.x509.read(chunk))
end
end
if options.ca then
if type(options.ca) == "string" then
ca = { assert(openssl.x509.read(options.ca)) }
elseif type(options.ca) == "table" then
ca = {}
for i = 1, #options.ca do
ca[i] = assert(openssl.x509.read(options.ca[i]))
end
else
error("options.ca must be string or table of strings")
end
end
if key and cert then
local first = table.remove(cert, 1)
assert(ctx:use(key, first))
if #cert > 0 then
-- TODO: find out if there is a way to not need to duplicate the last cert here
-- as a dummy fill for the root CA cert
assert(ctx:add(cert[#cert], cert))
end
end
if ca then
local store = openssl.x509.store:new()
for i = 1, #ca do
assert(store:add(ca[i]))
end
ctx:cert_store(store)
elseif DEFAULT_CA_STORE then
ctx:cert_store(DEFAULT_CA_STORE)
end
if not (options.insecure or options.key) then
ctx:verify_mode(openssl.ssl.peer, returnOne)
end
ctx:options(bit.bor(
openssl.ssl.no_sslv2,
openssl.ssl.no_sslv3,
openssl.ssl.no_compression))
return ctx
end

View File

@@ -0,0 +1,34 @@
--[[
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 getContext = require('./context')
local bioWrap = require('./biowrap')
return function (socket, options, callback)
if options == true then options = {} end
local ctx = getContext(options)
local thread
if not callback then
thread = coroutine.running()
end
bioWrap(ctx, options.server, socket, callback or function (err, ssocket)
return assert(coroutine.resume(thread, ssocket, err))
end, options.servername)
if not callback then
return coroutine.yield()
end
end

View File

@@ -0,0 +1,12 @@
return {
name = "luvit/secure-socket",
version = "1.2.2",
homepage = "https://github.com/luvit/luvit/blob/master/deps/secure-socket",
description = "Wrapper for luv streams to apply ssl/tls",
dependencies = {
"luvit/resource@2.1.0"
},
tags = {"ssl", "socket","tls"},
license = "Apache 2",
author = { name = "Tim Caswell" }
}

Binary file not shown.