refactor - fix various errors and add missing dependencies
This commit is contained in:
parent
928ed2d6ce
commit
8d63e39740
|
@ -0,0 +1,5 @@
|
|||
- utils refactoring
|
||||
- use resty.template for antibot
|
||||
- load inline values for white/black/grey list core
|
||||
- check if correct setting is set to yes in new() before loading stuff in self
|
||||
- store object in ngx.ctx
|
|
@ -1,38 +1,46 @@
|
|||
|
||||
local class = require "middleclass"
|
||||
local datastore = require "bunkerweb.datastore"
|
||||
local utils = require "bunkerweb.utils"
|
||||
local cjson = require "cjson"
|
||||
local upload = require "resty.upload"
|
||||
|
||||
local api = { global = { GET = {}, POST = {}, PUT = {}, DELETE = {} } }
|
||||
local api = class("api")
|
||||
|
||||
api.response = function(self, http_status, api_status, msg)
|
||||
api.global = { GET = {}, POST = {}, PUT = {}, DELETE = {} }
|
||||
|
||||
function api:initialize()
|
||||
self.datastore = datastore:new()
|
||||
end
|
||||
|
||||
function api:response(http_status, api_status, msg)
|
||||
local resp = {}
|
||||
resp["status"] = api_status
|
||||
resp["msg"] = msg
|
||||
return http_status, resp
|
||||
end
|
||||
|
||||
api.global.GET["^/ping$"] = function(api)
|
||||
return api:response(ngx.HTTP_OK, "success", "pong")
|
||||
api.global.GET["^/ping$"] = function(self)
|
||||
return self:response(ngx.HTTP_OK, "success", "pong")
|
||||
end
|
||||
|
||||
api.global.POST["^/reload$"] = function(api)
|
||||
api.global.POST["^/reload$"] = function(self)
|
||||
local status = os.execute("nginx -s reload")
|
||||
if status == 0 then
|
||||
return api:response(ngx.HTTP_OK, "success", "reload successful")
|
||||
return self:response(ngx.HTTP_OK, "success", "reload successful")
|
||||
end
|
||||
return api:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "exit status = " .. tostring(status))
|
||||
return self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "exit status = " .. tostring(status))
|
||||
end
|
||||
|
||||
api.global.POST["^/stop$"] = function(api)
|
||||
api.global.POST["^/stop$"] = function(self)
|
||||
local status = os.execute("nginx -s quit")
|
||||
if status == 0 then
|
||||
return api:response(ngx.HTTP_OK, "success", "stop successful")
|
||||
return self:response(ngx.HTTP_OK, "success", "stop successful")
|
||||
end
|
||||
return api:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "exit status = " .. tostring(status))
|
||||
return self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "exit status = " .. tostring(status))
|
||||
end
|
||||
|
||||
api.global.POST["^/confs$"] = function(api)
|
||||
api.global.POST["^/confs$"] = function(self)
|
||||
local tmp = "/var/tmp/bunkerweb/api_" .. ngx.var.uri:sub(2) .. ".tar.gz"
|
||||
local destination = "/usr/share/bunkerweb/" .. ngx.var.uri:sub(2)
|
||||
if ngx.var.uri == "/confs" then
|
||||
|
@ -48,7 +56,7 @@ api.global.POST["^/confs$"] = function(api)
|
|||
end
|
||||
local form, err = upload:new(4096)
|
||||
if not form then
|
||||
return api:response(ngx.HTTP_BAD_REQUEST, "error", err)
|
||||
return self:response(ngx.HTTP_BAD_REQUEST, "error", err)
|
||||
end
|
||||
form:set_timeout(1000)
|
||||
local file = io.open(tmp, "w+")
|
||||
|
@ -56,7 +64,7 @@ api.global.POST["^/confs$"] = function(api)
|
|||
local typ, res, err = form:read()
|
||||
if not typ then
|
||||
file:close()
|
||||
return api:response(ngx.HTTP_BAD_REQUEST, "error", err)
|
||||
return self:response(ngx.HTTP_BAD_REQUEST, "error", err)
|
||||
end
|
||||
if typ == "eof" then
|
||||
break
|
||||
|
@ -69,13 +77,13 @@ api.global.POST["^/confs$"] = function(api)
|
|||
file:close()
|
||||
local status = os.execute("rm -rf " .. destination .. "/*")
|
||||
if status ~= 0 then
|
||||
return api:response(ngx.HTTP_BAD_REQUEST, "error", "can't remove old files")
|
||||
return self:response(ngx.HTTP_BAD_REQUEST, "error", "can't remove old files")
|
||||
end
|
||||
status = os.execute("tar xzf " .. tmp .. " -C " .. destination)
|
||||
if status ~= 0 then
|
||||
return api:response(ngx.HTTP_BAD_REQUEST, "error", "can't extract archive")
|
||||
return self:response(ngx.HTTP_BAD_REQUEST, "error", "can't extract archive")
|
||||
end
|
||||
return api:response(ngx.HTTP_OK, "success", "saved data at " .. destination)
|
||||
return self:response(ngx.HTTP_OK, "success", "saved data at " .. destination)
|
||||
end
|
||||
|
||||
api.global.POST["^/data$"] = api.global.POST["^/confs$"]
|
||||
|
@ -86,7 +94,7 @@ api.global.POST["^/custom_configs$"] = api.global.POST["^/confs$"]
|
|||
|
||||
api.global.POST["^/plugins$"] = api.global.POST["^/confs$"]
|
||||
|
||||
api.global.POST["^/unban$"] = function(api)
|
||||
api.global.POST["^/unban$"] = function(self)
|
||||
ngx.req.read_body()
|
||||
local data = ngx.req.get_body_data()
|
||||
if not data then
|
||||
|
@ -99,13 +107,13 @@ api.global.POST["^/unban$"] = function(api)
|
|||
end
|
||||
local ok, ip = pcall(cjson.decode, data)
|
||||
if not ok then
|
||||
return api:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "can't decode JSON : " .. env)
|
||||
return self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "can't decode JSON : " .. env)
|
||||
end
|
||||
datastore:delete("bans_ip_" .. ip["ip"])
|
||||
return api:response(ngx.HTTP_OK, "success", "ip " .. ip["ip"] .. " unbanned")
|
||||
self.datastore:delete("bans_ip_" .. ip["ip"])
|
||||
return self:response(ngx.HTTP_OK, "success", "ip " .. ip["ip"] .. " unbanned")
|
||||
end
|
||||
|
||||
api.global.POST["^/ban$"] = function(api)
|
||||
api.global.POST["^/ban$"] = function(self)
|
||||
ngx.req.read_body()
|
||||
local data = ngx.req.get_body_data()
|
||||
if not data then
|
||||
|
@ -118,45 +126,45 @@ api.global.POST["^/ban$"] = function(api)
|
|||
end
|
||||
local ok, ip = pcall(cjson.decode, data)
|
||||
if not ok then
|
||||
return api:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "can't decode JSON : " .. env)
|
||||
return self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "can't decode JSON : " .. env)
|
||||
end
|
||||
datastore:set("bans_ip_" .. ip["ip"], "manual", ip["exp"])
|
||||
return api:response(ngx.HTTP_OK, "success", "ip " .. ip["ip"] .. " banned")
|
||||
self.datastore:set("bans_ip_" .. ip["ip"], "manual", ip["exp"])
|
||||
return self:response(ngx.HTTP_OK, "success", "ip " .. ip["ip"] .. " banned")
|
||||
end
|
||||
|
||||
api.global.GET["^/bans$"] = function(api)
|
||||
api.global.GET["^/bans$"] = function(self)
|
||||
local data = {}
|
||||
for i, k in ipairs(datastore:keys()) do
|
||||
for i, k in ipairs(self.datastore:keys()) do
|
||||
if k:find("^bans_ip_") then
|
||||
local ret, reason = datastore:get(k)
|
||||
if not ret then
|
||||
return api:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error",
|
||||
return self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error",
|
||||
"can't access " .. k .. " from datastore : " + reason)
|
||||
end
|
||||
local ret, exp = datastore:exp(k)
|
||||
local ret, exp = self.datastore:exp(k)
|
||||
if not ret then
|
||||
return api:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error",
|
||||
return self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error",
|
||||
"can't access exp " .. k .. " from datastore : " + exp)
|
||||
end
|
||||
local ban = { ip = k:sub(9, #k), reason = reason, exp = exp }
|
||||
table.insert(data, ban)
|
||||
end
|
||||
end
|
||||
return api:response(ngx.HTTP_OK, "success", data)
|
||||
return self:response(ngx.HTTP_OK, "success", data)
|
||||
end
|
||||
|
||||
api.is_allowed_ip = function(self)
|
||||
local data, err = datastore:get("api_whitelist_ip")
|
||||
function api:is_allowed_ip()
|
||||
local data, err = self.datastore:get("api_whitelist_ip")
|
||||
if not data then
|
||||
return false, "can't access api_allowed_ips in datastore"
|
||||
end
|
||||
if utils.is_ip_in_networks(ngx.var.remote_addr, cjson.decode(data).data) then
|
||||
if utils.is_ip_in_networks(ngx.var.remote_addr, cjson.decode(data)) then
|
||||
return true, "ok"
|
||||
end
|
||||
return false, "IP is not in API_WHITELIST_IP"
|
||||
end
|
||||
|
||||
api.do_api_call = function(self)
|
||||
function api:do_api_call()
|
||||
if self.global[ngx.var.request_method] ~= nil then
|
||||
for uri, api_fun in pairs(self.global[ngx.var.request_method]) do
|
||||
if string.match(ngx.var.uri, uri) then
|
||||
|
@ -175,7 +183,7 @@ api.do_api_call = function(self)
|
|||
end
|
||||
end
|
||||
end
|
||||
local list, err = datastore:get("plugins")
|
||||
local list, err = self.datastore:get("plugins")
|
||||
if not list then
|
||||
local status, resp = self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "can't list loaded plugins : " .. err)
|
||||
return false, resp["msg"], ngx.HTTP_INTERNAL_SERVER_ERROR, resp
|
||||
|
|
|
@ -35,15 +35,15 @@ local cache, err = mlcache.new(
|
|||
ipc_shm = ipc_shm
|
||||
}
|
||||
)
|
||||
logger:new("CACHESTORE")
|
||||
local module_logger = logger:new("CACHESTORE")
|
||||
if not cache then
|
||||
logger:log(ngx.ERR, "can't instantiate mlcache : " .. err)
|
||||
module_logger:log(ngx.ERR, "can't instantiate mlcache : " .. err)
|
||||
end
|
||||
|
||||
function cachestore:new(use_redis)
|
||||
function cachestore:initialize(use_redis)
|
||||
self.cache = cache
|
||||
self.use_redis = use_redis or false
|
||||
self.logger = logger
|
||||
self.logger = module_logger
|
||||
end
|
||||
|
||||
function cachestore:get(key)
|
||||
|
@ -96,7 +96,7 @@ function cachestore:get(key)
|
|||
else
|
||||
value, err, hit_level = self.cache:get(key)
|
||||
end
|
||||
if err then
|
||||
if value == nil and hit_level == nil then
|
||||
return false, err
|
||||
end
|
||||
self.logger:log(ngx.INFO, "hit level for " .. key .. " = " .. tostring(hit_level))
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
local class = require "middleclass"
|
||||
local utils = require "bunkerweb.utils"
|
||||
local logger = require "bunkerweb.logger"
|
||||
local redis = require "resty.redis"
|
||||
|
||||
local clusterstore = class("clusterstore")
|
||||
|
||||
function clusterstore:new()
|
||||
function clusterstore:initialize()
|
||||
-- Instantiate logger
|
||||
self.logger = logger:new("CLUSTERSTORE")
|
||||
-- Get variables
|
||||
local variables = {
|
||||
["REDIS_HOST"] = "",
|
||||
|
@ -20,16 +23,19 @@ function clusterstore:new()
|
|||
for k, v in pairs(variables) do
|
||||
local value, err = utils.get_variable(k, false)
|
||||
if value == nil then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
end
|
||||
self.variables[k] = value
|
||||
end
|
||||
-- Don't instantiate a redis object for now
|
||||
self.redis_client = nil
|
||||
return true, "success"
|
||||
end
|
||||
|
||||
function clusterstore:connect()
|
||||
-- Check if we are already connected
|
||||
if self.redis_client ~= nil then
|
||||
return true, "already connected"
|
||||
end
|
||||
-- Instantiate object
|
||||
local redis_client, err = redis:new()
|
||||
if redis_client == nil then
|
||||
|
@ -47,24 +53,28 @@ function clusterstore:connect()
|
|||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
-- Save client
|
||||
self.redis_client = redis_client
|
||||
-- Select database if needed
|
||||
local times, err = redis_client:get_reused_times()
|
||||
if err then
|
||||
self:close()
|
||||
return false, err
|
||||
end
|
||||
if times == 0 then
|
||||
local select, err = redis_client:select(tonumber(variables["REDIS_DATABASE"]))
|
||||
if err then
|
||||
self:close()
|
||||
return false, err
|
||||
end
|
||||
end
|
||||
self.redis_client = redis_client
|
||||
return return true, "success"
|
||||
return true, "success"
|
||||
end
|
||||
|
||||
function clusterstore:close()
|
||||
if self.redis_client then
|
||||
-- Equivalent to close but keep a pool of connections
|
||||
self.redis_client = nil
|
||||
return self.redis_client:set_keepalive(tonumber(self.variables["REDIS_KEEPALIVE_IDLE"]), tonumber(self.variables["REDIS_KEEPALIVE_POOL"]))
|
||||
end
|
||||
return false, "not connected"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
local class = require "middleclass"
|
||||
local datastore = class("datastore")
|
||||
|
||||
function datastore:new()
|
||||
function datastore:initialize()
|
||||
self.dict = ngx.shared.datastore
|
||||
if not self.dict then
|
||||
self.dict = ngx.shared.datastore_stream
|
||||
|
@ -16,21 +16,21 @@ function datastore:get(key)
|
|||
return value, err
|
||||
end
|
||||
|
||||
function datastore:set(self, key, value, exptime)
|
||||
function datastore:set(key, value, exptime)
|
||||
exptime = exptime or 0
|
||||
return self.dict:safe_set(key, value, exptime)
|
||||
end
|
||||
|
||||
function datastore:delete(self, key)
|
||||
function datastore:delete(key)
|
||||
self.dict:delete(key)
|
||||
return true, "success"
|
||||
end
|
||||
|
||||
function datastore:keys(self)
|
||||
function datastore:keys()
|
||||
return self.dict:get_keys(0)
|
||||
end
|
||||
|
||||
function datastore:exp(self, key)
|
||||
function datastore:exp(key)
|
||||
local ttl, err = self.dict:ttl(key)
|
||||
if not ttl then
|
||||
return false, err
|
||||
|
@ -38,7 +38,7 @@ function datastore:exp(self, key)
|
|||
return true, ttl
|
||||
end
|
||||
|
||||
function datastore:delete_all(self, pattern)
|
||||
function datastore:delete_all(pattern)
|
||||
local keys = self.dict:get_keys(0)
|
||||
for i, key in ipairs(keys) do
|
||||
if key:match(pattern) then
|
||||
|
|
|
@ -27,10 +27,10 @@ helpers.load_plugin = function(json)
|
|||
return false, "missing field(s) " .. cjson.encode(missing_fields) .. " for JSON at " .. json
|
||||
end
|
||||
-- Return plugin
|
||||
return plugin
|
||||
return true, plugin
|
||||
end
|
||||
|
||||
helpers.new_plugin = function(id)
|
||||
helpers.require_plugin = function(id)
|
||||
-- Require call
|
||||
local ok, plugin_lua = pcall(require, id .. "/" .. id)
|
||||
if not ok then
|
||||
|
@ -43,14 +43,19 @@ helpers.new_plugin = function(id)
|
|||
if plugin_lua.new == nil then
|
||||
return false, "missing new() method for plugin " .. id
|
||||
end
|
||||
local ok, err = pcall(plugin_lua.new, plugin_lua)
|
||||
if not ok then
|
||||
return false, "new() call failed for plugin " .. id .. " : " .. err
|
||||
end
|
||||
-- Return plugin
|
||||
return plugin_lua, "new() call successful for plugin " .. id
|
||||
end
|
||||
|
||||
helpers.new_plugin = function(plugin_lua)
|
||||
-- Require call
|
||||
local ok, plugin_obj = pcall(plugin_lua.new, plugin_lua)
|
||||
if not ok then
|
||||
return false, "new error for plugin " .. plugin_lua.name .. " : " .. plugin_obj
|
||||
end
|
||||
return true, plugin_obj
|
||||
end
|
||||
|
||||
helpers.call_plugin = function(plugin, method)
|
||||
-- Check if method is present
|
||||
if plugin[method] == nil then
|
||||
|
@ -59,7 +64,10 @@ helpers.call_plugin = function(plugin, method)
|
|||
-- Call method
|
||||
local ok, ret = pcall(plugin[method], plugin)
|
||||
if not ok then
|
||||
return false, plugin.id .. ":" .. method .. "() failed : " .. ret
|
||||
return false, plugin:get_id() .. ":" .. method .. "() failed : " .. ret
|
||||
end
|
||||
if ret == nil then
|
||||
return false, plugin:get_id() .. ":" .. method .. "() returned nil value"
|
||||
end
|
||||
-- Check values
|
||||
local missing_values = {}
|
||||
|
|
|
@ -2,8 +2,8 @@ local errlog = require "ngx.errlog"
|
|||
local class = require "middleclass"
|
||||
local logger = class("logger")
|
||||
|
||||
function logger:new(prefix)
|
||||
self.prefix = prefix
|
||||
function logger:initialize(prefix)
|
||||
self.prefix = string.upper(prefix)
|
||||
end
|
||||
|
||||
function logger:log(level, msg)
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
local class = require "middleclass"
|
||||
local logger = require "bunkerweb.logger"
|
||||
local datastore = require "bunkerweb.datastore"
|
||||
local datastore = require "bunkerweb.utils"
|
||||
local utils = require "bunkerweb.utils"
|
||||
local cjson = require "cjson"
|
||||
local plugin = class("plugin")
|
||||
|
||||
|
||||
function plugin:new(id)
|
||||
function plugin:initialize(id)
|
||||
-- Store default values
|
||||
self.id = id
|
||||
self.variables = {}
|
||||
-- Instantiate logger
|
||||
self.logger = require "bunkerweb.logger"
|
||||
self.logger:new(id)
|
||||
-- Instantiate objects
|
||||
self.logger = logger:new(id)
|
||||
self.datastore = datastore:new()
|
||||
-- Get metadata
|
||||
local encoded_metadata, err = datastore:get("plugin_" .. id)
|
||||
local encoded_metadata, err = self.datastore:get("plugin_" .. id)
|
||||
if not encoded_metadata then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
return
|
||||
end
|
||||
-- Store variables
|
||||
local metadata = cjson.decode(encoded_metadata)
|
||||
for k, v in pairs(metadata.settings) do
|
||||
local value, err = utils.get_variable(k, v.context == "multisite")
|
||||
local value, err = utils.get_variable(k, v.context == "multisite" and ngx.get_phase() ~= "init")
|
||||
if value == nil then
|
||||
return false, "can't get " .. k .. " variable : " .. err
|
||||
self.logger:log(ngx.ERR, "can't get " .. k .. " variable : " .. err)
|
||||
end
|
||||
self.variables[k] = value
|
||||
end
|
||||
return true, "success"
|
||||
end
|
||||
|
||||
function plugin:get_id()
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
local datastore = require "bunkerweb.datastore"
|
||||
local cdatastore = require "bunkerweb.datastore"
|
||||
local ipmatcher = require "resty.ipmatcher"
|
||||
local cjson = require "cjson"
|
||||
local resolver = require "resty.dns.resolver"
|
||||
local mmdb = require "bunkerweb.mmdb"
|
||||
local logger = require "bunkerweb.logger"
|
||||
local clogger = require "bunkerweb.logger"
|
||||
local session = require "resty.session"
|
||||
|
||||
logger:new("UTILS")
|
||||
local logger = clogger:new("UTILS")
|
||||
local datastore = cdatastore:new()
|
||||
|
||||
local utils = {}
|
||||
|
||||
|
@ -176,7 +177,7 @@ utils.ip_is_global = function(ip)
|
|||
if not ok then
|
||||
return nil, "can't decode json : " .. reserved_ips
|
||||
end
|
||||
local ipm, err = ipmatcher.new(reserved_ips.data)
|
||||
local ipm, err = ipmatcher.new(reserved_ips)
|
||||
if not ipm then
|
||||
return nil, "can't instantiate ipmatcher : " .. err
|
||||
end
|
||||
|
@ -418,4 +419,4 @@ utils.get_session = function(key)
|
|||
return false, "no session"
|
||||
end
|
||||
|
||||
return utils
|
||||
return utils
|
|
@ -15,24 +15,25 @@ server {
|
|||
|
||||
# check IP and do the API call
|
||||
access_by_lua_block {
|
||||
local api = require "bunkerweb.api"
|
||||
local logger = require "bunkerweb.logger"
|
||||
logger:new("API")
|
||||
local capi = require "bunkerweb.api"
|
||||
local clogger = require "bunkerweb.logger"
|
||||
local logger = clogger:new("API")
|
||||
local api = capi:new()
|
||||
if not ngx.var.http_host or ngx.var.http_host ~= "{{ API_SERVER_NAME }}" then
|
||||
logger.log(ngx.WARN, "wrong Host header from IP " .. ngx.var.remote_addr)
|
||||
logger:log(ngx.WARN, "wrong Host header from IP " .. ngx.var.remote_addr)
|
||||
return ngx.exit(ngx.HTTP_CLOSE)
|
||||
end
|
||||
local ok, err = api:is_allowed_ip()
|
||||
if not ok then
|
||||
logger.log(ngx.WARN, "can't validate access from IP " .. ngx.var.remote_addr .. " : " .. err)
|
||||
logger:log(ngx.WARN, "can't validate access from IP " .. ngx.var.remote_addr .. " : " .. err)
|
||||
return ngx.exit(ngx.HTTP_CLOSE)
|
||||
end
|
||||
logger.log(ngx.NOTICE, "validated access from IP " .. ngx.var.remote_addr)
|
||||
logger:log(ngx.NOTICE, "validated access from IP " .. ngx.var.remote_addr)
|
||||
local ok, err, status, resp = api:do_api_call()
|
||||
if not ok then
|
||||
logger.log(ngx.WARN, "call from " .. ngx.var.remote_addr .. " on " .. ngx.var.uri .. " failed : " .. err)
|
||||
logger:log(ngx.WARN, "call from " .. ngx.var.remote_addr .. " on " .. ngx.var.uri .. " failed : " .. err)
|
||||
else
|
||||
logger.log(ngx.NOTICE, "successful call from " .. ngx.var.remote_addr .. " on " .. ngx.var.uri .. " : " .. err)
|
||||
logger:log(ngx.NOTICE, "successful call from " .. ngx.var.remote_addr .. " on " .. ngx.var.uri .. " : " .. err)
|
||||
end
|
||||
ngx.status = status
|
||||
ngx.say(resp)
|
||||
|
|
|
@ -1,49 +1,50 @@
|
|||
init_by_lua_block {
|
||||
|
||||
local class = require "middleclass"
|
||||
local clogger = require "bunkerweb.logger"
|
||||
local logger = require "bunkerweb.logger"
|
||||
local helpers = require "bunkerweb.helpers"
|
||||
local datastore = require "bunkerweb.datastore"
|
||||
local cjson = require "cjson"
|
||||
|
||||
-- Start init phase
|
||||
logger:new("INIT")
|
||||
datastore:new()
|
||||
logger:log(ngx.NOTICE, "init phase started")
|
||||
local init_logger = logger:new("INIT")
|
||||
local ds = datastore:new()
|
||||
init_logger:log(ngx.NOTICE, "init phase started")
|
||||
|
||||
-- Remove previous data from the datastore
|
||||
logger:log(ngx.NOTICE, "deleting old keys from datastore ...")
|
||||
init_logger:log(ngx.NOTICE, "deleting old keys from datastore ...")
|
||||
local data_keys = {"^plugin_", "^variable_", "^plugins$", "^api_", "^misc_"}
|
||||
for i, key in pairs(data_keys) do
|
||||
local ok, err = datastore:delete_all(key)
|
||||
local ok, err = ds:delete_all(key)
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "can't delete " .. key .. " from datastore : " .. err)
|
||||
init_logger:log(ngx.ERR, "can't delete " .. key .. " from datastore : " .. err)
|
||||
return false
|
||||
end
|
||||
logger:log(ngx.INFO, "deleted " .. key .. " from datastore")
|
||||
init_logger:log(ngx.INFO, "deleted " .. key .. " from datastore")
|
||||
end
|
||||
logger:log(ngx.NOTICE, "deleted old keys from datastore")
|
||||
init_logger:log(ngx.NOTICE, "deleted old keys from datastore")
|
||||
|
||||
-- Load variables into the datastore
|
||||
logger:log(ngx.NOTICE, "saving variables into datastore ...")
|
||||
init_logger:log(ngx.NOTICE, "saving variables into datastore ...")
|
||||
local file = io.open("/etc/nginx/variables.env")
|
||||
if not file then
|
||||
logger:log(ngx.ERR, "can't open /etc/nginx/variables.env file")
|
||||
init_logger:log(ngx.ERR, "can't open /etc/nginx/variables.env file")
|
||||
return false
|
||||
end
|
||||
file:close()
|
||||
for line in io.lines("/etc/nginx/variables.env") do
|
||||
local variable, value = line:match("(.+)=(.*)")
|
||||
local ok, err = datastore:set("variable_" .. variable, value)
|
||||
local ok, err = ds:set("variable_" .. variable, value)
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "can't save variable " .. variable .. " into datastore : " .. err)
|
||||
init_logger:log(ngx.ERR, "can't save variable " .. variable .. " into datastore : " .. err)
|
||||
return false
|
||||
end
|
||||
logger:log(ngx.INFO, "saved variable " .. variable .. "=" .. value .. " into datastore")
|
||||
init_logger:log(ngx.INFO, "saved variable " .. variable .. "=" .. value .. " into datastore")
|
||||
end
|
||||
logger:log(ngx.NOTICE, "saved variables into datastore")
|
||||
init_logger:log(ngx.NOTICE, "saved variables into datastore")
|
||||
|
||||
-- Set misc values into the datastore
|
||||
logger:log(ngx.NOTICE, "saving misc values into datastore ...")
|
||||
init_logger:log(ngx.NOTICE, "saving misc values into datastore ...")
|
||||
local miscs = {
|
||||
reserved_ips = {
|
||||
"0.0.0.0/8",
|
||||
|
@ -65,107 +66,112 @@ local miscs = {
|
|||
},
|
||||
resolvers = {}
|
||||
}
|
||||
local var_resolvers, err = datastore:get("variable_DNS_RESOLVERS")
|
||||
local var_resolvers, err = ds:get("variable_DNS_RESOLVERS")
|
||||
if not var_resolvers then
|
||||
logger:log(ngx.ERR, "can't get variable DNS_RESOLVERS from datastore : " .. err)
|
||||
init_logger:log(ngx.ERR, "can't get variable DNS_RESOLVERS from datastore : " .. err)
|
||||
return false
|
||||
end
|
||||
for str_resolver in var_resolvers:gmatch("%S+") do
|
||||
table.insert(miscs.resolvers, str_resolver)
|
||||
end
|
||||
for k, v in pairs(miscs) do
|
||||
local ok, err = datastore:set("misc_" .. k, cjson.encode(v))
|
||||
local ok, err = ds:set("misc_" .. k, cjson.encode(v))
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "can't save misc " .. k .. " into datastore : " .. err)
|
||||
init_logger:log(ngx.ERR, "can't save misc " .. k .. " into datastore : " .. err)
|
||||
return false
|
||||
end
|
||||
logger:log(ngx.INFO, "saved misc " .. k .. " into datastore")
|
||||
init_logger:log(ngx.INFO, "saved misc " .. k .. " into datastore")
|
||||
end
|
||||
logger:log(ngx.NOTICE, "saved misc values into datastore")
|
||||
init_logger:log(ngx.NOTICE, "saved misc values into datastore")
|
||||
|
||||
-- Set API values into the datastore
|
||||
logger:log(ngx.NOTICE, "saving API values into datastore ...")
|
||||
local value, err = datastore:get("variable_USE_API")
|
||||
init_logger:log(ngx.NOTICE, "saving API values into datastore ...")
|
||||
local value, err = ds:get("variable_USE_API")
|
||||
if not value then
|
||||
logger:log(ngx.ERR, "can't get variable USE_API from the datastore : " .. err)
|
||||
init_logger:log(ngx.ERR, "can't get variable USE_API from the datastore : " .. err)
|
||||
return false
|
||||
end
|
||||
if value == "yes" then
|
||||
local value, err = datastore:get("variable_API_WHITELIST_IP")
|
||||
local value, err = ds:get("variable_API_WHITELIST_IP")
|
||||
if not value then
|
||||
logger:log(ngx.ERR, "can't get variable API_WHITELIST_IP from the datastore : " .. err)
|
||||
init_logger:log(ngx.ERR, "can't get variable API_WHITELIST_IP from the datastore : " .. err)
|
||||
return false
|
||||
end
|
||||
local whitelists = {}
|
||||
for whitelist in value:gmatch("%S+") do
|
||||
table.insert(whitelists, whitelist)
|
||||
end
|
||||
local ok, err = datastore:set("api_whitelist_ip", cjson.encode(whitelists))
|
||||
local ok, err = ds:set("api_whitelist_ip", cjson.encode(whitelists))
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "can't save API whitelist_ip to datastore : " .. err)
|
||||
init_logger:log(ngx.ERR, "can't save API whitelist_ip to datastore : " .. err)
|
||||
return false
|
||||
end
|
||||
logger:log(ngx.INFO, "saved API whitelist_ip into datastore")
|
||||
init_logger:log(ngx.INFO, "saved API whitelist_ip into datastore")
|
||||
end
|
||||
logger:log(ngx.NOTICE, "saved API values into datastore")
|
||||
init_logger:log(ngx.NOTICE, "saved API values into datastore")
|
||||
|
||||
-- Load plugins into the datastore
|
||||
logger:log(ngx.NOTICE, "saving plugins into datastore ...")
|
||||
init_logger:log(ngx.NOTICE, "saving plugins into datastore ...")
|
||||
local plugins = {}
|
||||
local plugin_paths = {"/usr/share/bunkerweb/core", "/etc/bunkerweb/plugins"}
|
||||
for i, plugin_path in ipairs(plugin_paths) do
|
||||
local paths = io.popen("find -L " .. plugin_path .. " -maxdepth 1 -type d ! -path " .. plugin_path)
|
||||
for path in paths:lines() do
|
||||
local ok, plugin = helpers.load_plugin(path .. "/plugin.json")
|
||||
if ok then
|
||||
logger:log(ngx.ERR, err)
|
||||
if not ok then
|
||||
init_logger:log(ngx.ERR, plugin)
|
||||
else
|
||||
local ok, err = datastore:set("plugin_" .. plugin.id, cjson.encode(plugin))
|
||||
local ok, err = ds:set("plugin_" .. plugin.id, cjson.encode(plugin))
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "can't save " .. plugin.id .. " into datastore : " .. err)
|
||||
init_logger:log(ngx.ERR, "can't save " .. plugin.id .. " into datastore : " .. err)
|
||||
else
|
||||
table.insert(plugins, plugin)
|
||||
table.sort(plugins, function (a, b)
|
||||
return a.order < b.order
|
||||
end)
|
||||
logger:log(ngx.NOTICE, "loaded plugin " .. plugin.id .. " v" .. plugin.version)
|
||||
init_logger:log(ngx.NOTICE, "loaded plugin " .. plugin.id .. " v" .. plugin.version)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local ok, err = datastore:set("plugins", cjson.encode(plugins))
|
||||
local ok, err = ds:set("plugins", cjson.encode(plugins))
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "can't save plugins into datastore : " .. err)
|
||||
init_logger:log(ngx.ERR, "can't save plugins into datastore : " .. err)
|
||||
return false
|
||||
end
|
||||
logger:log(ngx.NOTICE, "saved plugins into datastore")
|
||||
init_logger:log(ngx.NOTICE, "saved plugins into datastore")
|
||||
|
||||
-- Call init() methods
|
||||
logger:log(ngx.NOTICE, "calling init() methods of plugins ...")
|
||||
init_logger:log(ngx.NOTICE, "calling init() methods of plugins ...")
|
||||
for i, plugin in ipairs(plugins) do
|
||||
local plugin_lua, err = helpers.new_plugin(plugin.id)
|
||||
-- Require call
|
||||
local plugin_lua, err = helpers.require_plugin(plugin.id)
|
||||
if plugin_lua == false then
|
||||
logger:log(ngx.ERR, err)
|
||||
init_logger:log(ngx.ERR, err)
|
||||
elseif plugin_lua == nil then
|
||||
init_logger:log(ngx.NOTICE, err)
|
||||
else
|
||||
logger:log(ngx.NOTICE, err)
|
||||
end
|
||||
if plugin_lua ~= nil then
|
||||
local ok, ret = helpers.call_plugin(plugin_lua, "init")
|
||||
if ok == false then
|
||||
logger:log(ngx.ERR, ret)
|
||||
elseif ok == nil then
|
||||
logger:log(ngx.NOTICE, ret)
|
||||
else
|
||||
if ret.ret then
|
||||
logger:log(ngx.NOTICE, plugin.id .. ":init() call successful : " .. ret.msg)
|
||||
-- Check if plugin has init method
|
||||
if plugin_lua.init ~= nil then
|
||||
-- New call
|
||||
local ok, plugin_obj = helpers.new_plugin(plugin_lua)
|
||||
if not ok then
|
||||
init_logger:log(ngx.ERR, plugin_obj)
|
||||
else
|
||||
logger:log(ngx.ERR, plugin.id .. ":init() call failed : " .. ret.msg)
|
||||
local ok, ret = helpers.call_plugin(plugin_obj, "init")
|
||||
if not ok then
|
||||
init_logger:log(ngx.ERR, ret)
|
||||
else
|
||||
init_logger:log(ngx.NOTICE, plugin.id .. ":init() call successful : " .. ret.msg)
|
||||
end
|
||||
end
|
||||
else
|
||||
init_logger:log(ngx.NOTICE, "skipped execution of " .. plugin.id .. " because method init() is not defined")
|
||||
end
|
||||
end
|
||||
end
|
||||
logger:log(ngx.NOTICE, "called init() methods of plugins")
|
||||
init_logger:log(ngx.NOTICE, "called init() methods of plugins")
|
||||
|
||||
logger:log(ngx.NOTICE, "init phase ended")
|
||||
init_logger:log(ngx.NOTICE, "init phase ended")
|
||||
|
||||
}
|
||||
|
|
|
@ -3,25 +3,39 @@ access_by_lua_block {
|
|||
local class = require "middleclass"
|
||||
local clogger = require "bunkerweb.logger"
|
||||
local helpers = require "bunkerweb.helpers"
|
||||
local datastore = require "bunkerweb.datastore"
|
||||
local utils = require "bunkerweb.utils"
|
||||
local cdatastore = require "bunkerweb.datastore"
|
||||
local ccachestore = require "bunkerweb.cachestore"
|
||||
local cjson = require "cjson"
|
||||
|
||||
-- Don't process internal requests
|
||||
logger:new("ACCESS")
|
||||
local logger = clogger:new("ACCESS")
|
||||
if ngx.req.is_internal() then
|
||||
logger:log(ngx.INFO, "skipped access phase because request is internal")
|
||||
return true
|
||||
end
|
||||
|
||||
-- Start access phase
|
||||
datastore:new()
|
||||
local datastore = cdatastore:new()
|
||||
local use_redis, err = utils.get_variable("USE_REDIS", false)
|
||||
if not use_redis then
|
||||
logger:log(ngx.ERR, err)
|
||||
end
|
||||
local cachestore = ccachestore:new(use_redis == "yes")
|
||||
logger:log(ngx.INFO, "access phase started")
|
||||
|
||||
-- Update cachestore only once and before any other code
|
||||
local ok, err = cachestore.cache:update()
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "can't update cachestore : " .. err)
|
||||
end
|
||||
|
||||
-- Process bans as soon as possible
|
||||
local ok, reason = cachestore:get("bans_ip_" .. ngx.var.remote_addr)
|
||||
if not ok and reason then
|
||||
logger:log(ngx.INFO, "error while checking if client is banned : " .. reason)
|
||||
return false
|
||||
else reason then
|
||||
elseif reason then
|
||||
logger:log(ngx.WARN, "IP " .. ngx.var.remote_addr .. " is banned with reason : " .. reason)
|
||||
return ngx.exit(utils.get_deny_status())
|
||||
end
|
||||
|
@ -32,25 +46,31 @@ if not plugins then
|
|||
logger:log(ngx.ERR, "can't get plugins from datastore : " .. err)
|
||||
return false
|
||||
end
|
||||
plugins = cjson.decode(plugins)
|
||||
|
||||
-- Call access() methods
|
||||
logger:log(ngx.INFO, "calling access() methods of plugins ...")
|
||||
for i, plugin in ipairs(plugins) do
|
||||
local plugin_lua, err = helpers.new_plugin(plugin.id)
|
||||
-- Require call
|
||||
local plugin_lua, err = helpers.require_plugin(plugin.id)
|
||||
if plugin_lua == false then
|
||||
logger:log(ngx.ERR, err)
|
||||
else
|
||||
elseif plugin_lua == nil then
|
||||
logger:log(ngx.INFO, err)
|
||||
end
|
||||
if plugin_lua ~= nil then
|
||||
local ok, ret = helpers.call_plugin(plugin_lua, "access")
|
||||
if ok == false then
|
||||
logger:log(ngx.ERR, ret)
|
||||
elseif ok == nil then
|
||||
logger:log(ngx.INFO, ret)
|
||||
else
|
||||
if ret.ret then
|
||||
logger:log(ngx.INFO, plugin.id .. ":access() call successful : " .. ret.msg)
|
||||
else
|
||||
-- Check if plugin has access method
|
||||
if plugin_lua.access ~= nil then
|
||||
-- New call
|
||||
local ok, plugin_obj = helpers.new_plugin(plugin_lua)
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, plugin_obj)
|
||||
else
|
||||
local ok, ret = helpers.call_plugin(plugin_obj, "access")
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, ret)
|
||||
else
|
||||
logger:log(ngx.INFO, plugin.id .. ":access() call successful : " .. ret.msg)
|
||||
end
|
||||
if ret.status then
|
||||
if ret.status == utils.get_deny_status() then
|
||||
ngx.ctx.reason = plugin.id
|
||||
|
@ -63,10 +83,11 @@ for i, plugin in ipairs(plugins) do
|
|||
elseif ret.redirect then
|
||||
logger:log(ngx.NOTICE, plugin.id .. " redirect to " .. ret.redirect .. " : " .. err)
|
||||
ngx.ctx.redirect = ret.redirect
|
||||
break
|
||||
end
|
||||
else
|
||||
logger:log(ngx.ERR, plugin.id .. ":access() call failed : " .. ret.msg)
|
||||
end
|
||||
else
|
||||
logger:log(ngx.INFO, "skipped execution of " .. plugin.id .. " because method access() is not defined")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
header_filter_by_lua_block {
|
||||
|
||||
local class = require "middleclass"
|
||||
local clogger = require "bunkerweb.logger"
|
||||
local helpers = require "bunkerweb.helpers"
|
||||
local cdatastore = require "bunkerweb.datastore"
|
||||
local cjson = require "cjson"
|
||||
|
||||
-- Don't process internal requests
|
||||
local logger = clogger:new("HEADER")
|
||||
if ngx.req.is_internal() then
|
||||
logger:log(ngx.INFO, "skipped header phase because request is internal")
|
||||
return true
|
||||
end
|
||||
|
||||
-- Start set phase
|
||||
local datastore = cdatastore:new()
|
||||
logger:log(ngx.INFO, "header phase started")
|
||||
|
||||
-- Get plugins
|
||||
local plugins, err = datastore:get("plugins")
|
||||
if not plugins then
|
||||
logger:log(ngx.ERR, "can't get plugins from datastore : " .. err)
|
||||
return false
|
||||
end
|
||||
plugins = cjson.decode(plugins)
|
||||
|
||||
-- Call header() methods
|
||||
logger:log(ngx.INFO, "calling header() methods of plugins ...")
|
||||
for i, plugin in ipairs(plugins) do
|
||||
-- Require call
|
||||
local plugin_lua, err = helpers.require_plugin(plugin.id)
|
||||
if plugin_lua == false then
|
||||
logger:log(ngx.ERR, err)
|
||||
elseif plugin_lua == nil then
|
||||
logger:log(ngx.INFO, err)
|
||||
else
|
||||
-- Check if plugin has header method
|
||||
if plugin_lua.header ~= nil then
|
||||
-- New call
|
||||
local ok, plugin_obj = helpers.new_plugin(plugin_lua)
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, plugin_obj)
|
||||
else
|
||||
local ok, ret = helpers.call_plugin(plugin_obj, "header")
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, ret)
|
||||
else
|
||||
logger:log(ngx.INFO, plugin.id .. ":header() call successful : " .. ret.msg)
|
||||
end
|
||||
end
|
||||
else
|
||||
logger:log(ngx.INFO, "skipped execution of " .. plugin.id .. " because method header() is not defined")
|
||||
end
|
||||
end
|
||||
end
|
||||
logger:log(ngx.INFO, "called header() methods of plugins")
|
||||
|
||||
return true
|
||||
|
||||
}
|
|
@ -3,11 +3,12 @@ log_by_lua_block {
|
|||
local class = require "middleclass"
|
||||
local clogger = require "bunkerweb.logger"
|
||||
local helpers = require "bunkerweb.helpers"
|
||||
local datastore = require "bunkerweb.datastore"
|
||||
local cdatastore = require "bunkerweb.datastore"
|
||||
local cjson = require "cjson"
|
||||
|
||||
-- Start log phase
|
||||
logger:new("LOG")
|
||||
datastore:new()
|
||||
local logger = clogger:new("LOG")
|
||||
local datastore = cdatastore:new()
|
||||
logger:log(ngx.INFO, "log phase started")
|
||||
|
||||
-- Get plugins
|
||||
|
@ -16,28 +17,34 @@ if not plugins then
|
|||
logger:log(ngx.ERR, "can't get plugins from datastore : " .. err)
|
||||
return false
|
||||
end
|
||||
plugins = cjson.decode(plugins)
|
||||
|
||||
-- Call log() methods
|
||||
logger:log(ngx.INFO, "calling log() methods of plugins ...")
|
||||
for i, plugin in ipairs(plugins) do
|
||||
local plugin_lua, err = helpers.new_plugin(plugin.id)
|
||||
-- Require call
|
||||
local plugin_lua, err = helpers.require_plugin(plugin.id)
|
||||
if plugin_lua == false then
|
||||
logger:log(ngx.ERR, err)
|
||||
else
|
||||
elseif plugin_lua == nil then
|
||||
logger:log(ngx.INFO, err)
|
||||
end
|
||||
if plugin_lua ~= nil then
|
||||
local ok, ret = helpers.call_plugin(plugin_lua, "log")
|
||||
if ok == false then
|
||||
logger:log(ngx.ERR, ret)
|
||||
elseif ok == nil then
|
||||
logger:log(ngx.INFO, ret)
|
||||
else
|
||||
if ret.ret then
|
||||
logger:log(ngx.INFO, plugin.id .. ":log() call successful : " .. ret.msg)
|
||||
else
|
||||
-- Check if plugin has log method
|
||||
if plugin_lua.log ~= nil then
|
||||
-- New call
|
||||
local ok, plugin_obj = helpers.new_plugin(plugin_lua)
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, plugin_obj)
|
||||
else
|
||||
logger:log(ngx.ERR, plugin.id .. ":log() call failed : " .. ret.msg)
|
||||
local ok, ret = helpers.call_plugin(plugin_obj, "log")
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, ret)
|
||||
else
|
||||
logger:log(ngx.INFO, plugin.id .. ":log() call successful : " .. ret.msg)
|
||||
end
|
||||
end
|
||||
else
|
||||
logger:log(ngx.INFO, "skipped execution of " .. plugin.id .. " because method log() is not defined")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,57 +2,56 @@ set $dummy_set "";
|
|||
set_by_lua_block $dummy_set {
|
||||
|
||||
local class = require "middleclass"
|
||||
local logger = require "bunkerweb.logger"
|
||||
local clogger = require "bunkerweb.logger"
|
||||
local helpers = require "bunkerweb.helpers"
|
||||
local datastore = require "bunkerweb.datastore"
|
||||
local cachestore = require "bunkerweb.cachestore"
|
||||
local cdatastore = require "bunkerweb.datastore"
|
||||
local cjson = require "cjson"
|
||||
|
||||
-- Don't process internal requests
|
||||
logger:new("SET")
|
||||
local logger = clogger:new("SET")
|
||||
if ngx.req.is_internal() then
|
||||
logger:log(ngx.INFO, "skipped access phase because request is internal")
|
||||
logger:log(ngx.INFO, "skipped set phase because request is internal")
|
||||
return true
|
||||
end
|
||||
|
||||
-- Start set phase
|
||||
datastore:new()
|
||||
local datastore = cdatastore:new()
|
||||
logger:log(ngx.INFO, "set phase started")
|
||||
|
||||
-- Update cachestore only once and before any other code
|
||||
cachestore:new()
|
||||
local ok, err = cachestore.cache:update()
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "can't update cachestore : " .. err)
|
||||
end
|
||||
|
||||
-- Get plugins
|
||||
local plugins, err = datastore:get("plugins")
|
||||
if not plugins then
|
||||
logger:log(ngx.ERR, "can't get plugins from datastore : " .. err)
|
||||
return false
|
||||
end
|
||||
plugins = cjson.decode(plugins)
|
||||
|
||||
-- Call set() methods
|
||||
logger:log(ngx.INFO, "calling set() methods of plugins ...")
|
||||
for i, plugin in ipairs(plugins) do
|
||||
local plugin_lua, err = helpers.new_plugin(plugin.id)
|
||||
-- Require call
|
||||
local plugin_lua, err = helpers.require_plugin(plugin.id)
|
||||
if plugin_lua == false then
|
||||
logger:log(ngx.ERR, err)
|
||||
else
|
||||
elseif plugin_lua == nil then
|
||||
logger:log(ngx.INFO, err)
|
||||
end
|
||||
if plugin_lua ~= nil then
|
||||
local ok, ret = helpers.call_plugin(plugin_lua, "set")
|
||||
if ok == false then
|
||||
logger:log(ngx.ERR, ret)
|
||||
elseif ok == nil then
|
||||
logger:log(ngx.INFO, ret)
|
||||
else
|
||||
if ret.ret then
|
||||
logger:log(ngx.INFO, plugin.id .. ":set() call successful : " .. ret.msg)
|
||||
else
|
||||
-- Check if plugin has set method
|
||||
if plugin_lua.set ~= nil then
|
||||
-- New call
|
||||
local ok, plugin_obj = helpers.new_plugin(plugin_lua)
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, plugin_obj)
|
||||
else
|
||||
logger:log(ngx.ERR, plugin.id .. ":set() call failed : " .. ret.msg)
|
||||
local ok, ret = helpers.call_plugin(plugin_obj, "set")
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, ret)
|
||||
else
|
||||
logger:log(ngx.INFO, plugin.id .. ":set() call successful : " .. ret.msg)
|
||||
end
|
||||
end
|
||||
else
|
||||
logger:log(ngx.INFO, "skipped execution of " .. plugin.id .. " because method set() is not defined")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,6 @@ local class = require "middleclass"
|
|||
local plugin = require "bunkerweb.plugin"
|
||||
local utils = require "bunkerweb.utils"
|
||||
local datastore = require "bunkerweb.datastore"
|
||||
local logger = require "bunkerweb.logger"
|
||||
local cjson = require "cjson"
|
||||
local captcha = require "antibot.captcha"
|
||||
local base64 = require "base64"
|
||||
|
@ -12,21 +11,17 @@ local http = require "resty.http"
|
|||
|
||||
local antibot = class("antibot", plugin)
|
||||
|
||||
function antibot:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "antibot")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
function antibot:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "antibot")
|
||||
-- Check if init is needed
|
||||
if ngx.get_phase() == "init" then
|
||||
local init_needed, err = utils.has_not_variable("USE_ANTIBOT", "no")
|
||||
if init_needed == nil then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
end
|
||||
self.init_needed = init_needed
|
||||
end
|
||||
return true, "success"
|
||||
end
|
||||
|
||||
function antibot:init()
|
||||
|
@ -41,7 +36,7 @@ function antibot:init()
|
|||
templates[template] = f:read("*all")
|
||||
f:close()
|
||||
end
|
||||
local ok, err = datastore:set("plugin_antibot_templates", cjson.encode(templates))
|
||||
local ok, err = self.datastore:set("plugin_antibot_templates", cjson.encode(templates))
|
||||
if not ok then
|
||||
return self:ret(false, "can't save templates to datastore : " .. err)
|
||||
end
|
||||
|
@ -201,7 +196,7 @@ function antibot:display_challenge(challenge_uri)
|
|||
end
|
||||
|
||||
-- Load HTML templates
|
||||
local str_templates, err = datastore:get("plugin_antibot_templates")
|
||||
local str_templates, err = self.datastore:get("plugin_antibot_templates")
|
||||
if not str_templates then
|
||||
return false, "can't get templates from datastore : " .. err
|
||||
end
|
||||
|
@ -364,4 +359,4 @@ function antibot:check_challenge()
|
|||
return nil, "unknown", nil
|
||||
end
|
||||
|
||||
return _M
|
||||
return antibot
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
local _M = {}
|
||||
|
||||
local gd = require 'gd'
|
||||
local logger = require "logger"
|
||||
|
||||
local mt = { __index = {} }
|
||||
|
||||
|
|
|
@ -6,19 +6,15 @@ local clusterstore = require "bunkerweb.clusterstore"
|
|||
|
||||
local badbehavior = class("badbehavior", plugin)
|
||||
|
||||
function badbehavior:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "badbehavior")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
function badbehavior:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "badbehavior")
|
||||
-- Check if redis is enabled
|
||||
local use_redis, err = utils.get_variable("USE_REDIS", false)
|
||||
if not use_redis then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
end
|
||||
self.use_redis = use_redis == "yes"
|
||||
return true, "success"
|
||||
end
|
||||
|
||||
function badbehavior:log()
|
||||
|
|
|
@ -8,71 +8,70 @@ local ipmatcher = require "resty.ipmatcher"
|
|||
|
||||
local blacklist = class("blacklist", plugin)
|
||||
|
||||
function blacklist:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "blacklist")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
function blacklist:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "blacklist")
|
||||
-- Check if redis is enabled
|
||||
local use_redis, err = utils.get_variable("USE_REDIS", false)
|
||||
if not use_redis then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
end
|
||||
self.use_redis = use_redis == "yes"
|
||||
-- Check if init is needed
|
||||
if ngx.get_phase() == "init" then
|
||||
local init_needed, err = utils.has_variable("USE_BLACKLIST", "yes")
|
||||
if init_needed == nil then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
end
|
||||
self.init_needed = init_needed
|
||||
-- Decode lists
|
||||
else
|
||||
local lists, err = datastore:get("plugin_blacklist_lists")
|
||||
local lists, err = self.datastore:get("plugin_blacklist_lists")
|
||||
if not lists then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
else
|
||||
self.lists = cjson.decode(lists)
|
||||
end
|
||||
self.lists = cjson.decode(lists)
|
||||
end
|
||||
-- Instantiate cachestore
|
||||
cachestore:new(use_redis)
|
||||
return true, "success"
|
||||
self.cachestore = cachestore:new(self.use_redis)
|
||||
end
|
||||
|
||||
function blacklist:init()
|
||||
if self.init_needed then
|
||||
-- Read blacklists
|
||||
local blacklists = {
|
||||
["IP"] = {},
|
||||
["RDNS"] = {},
|
||||
["ASN"] = {},
|
||||
["USER_AGENT"] = {},
|
||||
["URI"] = {},
|
||||
["IGNORE_IP"] = {},
|
||||
["IGNORE_RDNS"] = {},
|
||||
["IGNORE_ASN"] = {},
|
||||
["IGNORE_USER_AGENT"] = {},
|
||||
["IGNORE_URI"] = {},
|
||||
}
|
||||
local i = 0
|
||||
for kind, _ in pairs(blacklists) do
|
||||
local f, err = io.open("/var/cache/bunkerweb/blacklist/" .. kind .. ".list", "r")
|
||||
if f then
|
||||
for line in f:lines() do
|
||||
table.insert(blacklists[kind], line)
|
||||
i = i + 1
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
-- Load them into datastore
|
||||
local ok, err = datastore:set("plugin_blacklist_lists", cjson.encode(blacklists))
|
||||
if not ok then
|
||||
return self:ret(false, "can't store blacklist list into datastore : " .. err)
|
||||
end
|
||||
return self:ret(true, "successfully loaded " .. tostring(i) .. " IP/network/rDNS/ASN/User-Agent/URI")
|
||||
-- Check if init is needed
|
||||
if not self.init_needed then
|
||||
return self:ret(true, "init not needed")
|
||||
end
|
||||
-- Read blacklists
|
||||
local blacklists = {
|
||||
["IP"] = {},
|
||||
["RDNS"] = {},
|
||||
["ASN"] = {},
|
||||
["USER_AGENT"] = {},
|
||||
["URI"] = {},
|
||||
["IGNORE_IP"] = {},
|
||||
["IGNORE_RDNS"] = {},
|
||||
["IGNORE_ASN"] = {},
|
||||
["IGNORE_USER_AGENT"] = {},
|
||||
["IGNORE_URI"] = {},
|
||||
}
|
||||
local i = 0
|
||||
for kind, _ in pairs(blacklists) do
|
||||
local f, err = io.open("/var/cache/bunkerweb/blacklist/" .. kind .. ".list", "r")
|
||||
if f then
|
||||
for line in f:lines() do
|
||||
table.insert(blacklists[kind], line)
|
||||
i = i + 1
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
-- Load them into datastore
|
||||
local ok, err = self.datastore:set("plugin_blacklist_lists", cjson.encode(blacklists))
|
||||
if not ok then
|
||||
return self:ret(false, "can't store blacklist list into datastore : " .. err)
|
||||
end
|
||||
return self:ret(true, "successfully loaded " .. tostring(i) .. " IP/network/rDNS/ASN/User-Agent/URI")
|
||||
end
|
||||
|
||||
function blacklist:access()
|
||||
|
@ -97,7 +96,7 @@ function blacklist:access()
|
|||
}
|
||||
for k, v in pairs(checks) do
|
||||
local ok, cached = self:is_in_cache(v)
|
||||
if not cached then
|
||||
if not ok then
|
||||
self.logger:log(ngx.ERR, "error while checking cache : " .. cached)
|
||||
elseif cached and cached ~= "ok" then
|
||||
return self:ret(true, k + " is in cached blacklist (info : " .. cached .. ")", utils.get_deny_status())
|
||||
|
@ -115,9 +114,9 @@ function blacklist:access()
|
|||
if not already_cached[k] then
|
||||
local ok, blacklisted = self:is_blacklisted(k)
|
||||
if ok == nil then
|
||||
self.logger:log(ngx.ERR, "error while checking if " .. k .. " is blacklisted : " .. err)
|
||||
self.logger:log(ngx.ERR, "error while checking if " .. k .. " is blacklisted : " .. blacklisted)
|
||||
else
|
||||
local ok, err = self:add_to_cache(v, blacklisted)
|
||||
local ok, err = self:add_to_cache(self:kind_to_ele(k), blacklisted)
|
||||
if not ok then
|
||||
self.logger:log(ngx.ERR, "error while adding element to cache : " .. err)
|
||||
end
|
||||
|
@ -137,17 +136,27 @@ function blacklist:preread()
|
|||
return self:access()
|
||||
end
|
||||
|
||||
function blacklist:kind_to_ele(kind)
|
||||
if kind == "IP" then
|
||||
return "ip" .. ngx.var.remote_addr
|
||||
elseif kind == "UA" then
|
||||
return "ua" .. ngx.var.http_user_agent
|
||||
elseif kind == "URI" then
|
||||
return "uri" .. ngx.var.uri
|
||||
end
|
||||
end
|
||||
|
||||
function blacklist:is_in_cache(ele)
|
||||
local ok, data = cachestore:get("plugin_blacklist_" .. ele)
|
||||
if not ok then then
|
||||
local ok, data = self.cachestore:get("plugin_blacklist_" .. ele)
|
||||
if not ok then
|
||||
return false, data
|
||||
end
|
||||
return true, data
|
||||
end
|
||||
|
||||
function blacklist:add_to_cache(ele, value)
|
||||
local ok, err = cachestore:set("plugin_blacklist_" .. ele, value)
|
||||
if not ok then then
|
||||
local ok, err = self.cachestore:set("plugin_blacklist_" .. ele, value)
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
return true
|
||||
|
@ -156,10 +165,11 @@ end
|
|||
function blacklist:is_blacklisted(kind)
|
||||
if kind == "IP" then
|
||||
return self:is_blacklisted_ip()
|
||||
elseif kind == "URI"
|
||||
elseif kind == "URI" then
|
||||
return self:is_blacklisted_uri()
|
||||
elseif kind == "UA"
|
||||
elseif kind == "UA" then
|
||||
return self:is_blacklisted_ua()
|
||||
end
|
||||
return false, "unknown kind " .. kind
|
||||
end
|
||||
|
||||
|
|
|
@ -7,29 +7,25 @@ local http = require "resty.http"
|
|||
|
||||
local bunkernet = class("bunkernet", plugin)
|
||||
|
||||
function bunkernet:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "bunkernet")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
function bunkernet:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "bunkernet")
|
||||
-- Check if init is needed
|
||||
if ngx.get_phase() == "init" then
|
||||
local init_needed, err = utils.has_variable("USE_BUNKERNET", "yes")
|
||||
if init_needed == nil then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
end
|
||||
self.init_needed = true
|
||||
self.init_needed = init_needed
|
||||
-- Get BunkerNet ID
|
||||
else
|
||||
local id, err = datastore:get("plugin_bunkernet_id")
|
||||
local id, err = self.datastore:get("plugin_bunkernet_id")
|
||||
if not id then
|
||||
self.bunkernet_id = nil
|
||||
else
|
||||
self.bunkernet_id = id
|
||||
end
|
||||
end
|
||||
return true, "success"
|
||||
end
|
||||
|
||||
function bunkernet:init()
|
||||
|
@ -46,7 +42,7 @@ function bunkernet:init()
|
|||
id = f:read("*all"):gsub("[\r\n]", "")
|
||||
f:close()
|
||||
-- Store ID in datastore
|
||||
local ok, err = datastore:set("plugin_bunkernet_id", id)
|
||||
local ok, err = self.datastore:set("plugin_bunkernet_id", id)
|
||||
if not ok then
|
||||
return self:ret(false, "can't save instance ID to the datastore : " .. err)
|
||||
end
|
||||
|
@ -71,7 +67,7 @@ function bunkernet:init()
|
|||
return self:ret(false, "error while reading database : " .. err)
|
||||
end
|
||||
f:close()
|
||||
local ok, err = datastore:set("plugin_bunkernet_db", cjson.encode(db))
|
||||
local ok, err = self.datastore:set("plugin_bunkernet_db", cjson.encode(db))
|
||||
if not ok then
|
||||
return self:ret(false, "can't store bunkernet database into datastore : " .. err)
|
||||
end
|
||||
|
|
|
@ -4,12 +4,9 @@ local utils = require "bunkerweb.utils"
|
|||
|
||||
local cors = class("cors", plugin)
|
||||
|
||||
function cors:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "cors")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
function cors:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "cors")
|
||||
end
|
||||
|
||||
function cors:header()
|
||||
|
@ -28,7 +25,7 @@ function cors:header()
|
|||
}
|
||||
for variable, header in pairs(cors_headers) do
|
||||
local value = self.variables[variable]
|
||||
elseif value ~= "" then
|
||||
if value ~= "" then
|
||||
ngx.header[header] = value
|
||||
end
|
||||
end
|
||||
|
@ -36,7 +33,7 @@ function cors:header()
|
|||
ngx.header["Content-Length"] = "0"
|
||||
|
||||
-- Send CORS policy with a 204 (no content) status
|
||||
return return self:ret(true, "sent CORS policy", ngx.HTTP_NO_CONTENT)
|
||||
return self:ret(true, "sent CORS policy")
|
||||
end
|
||||
|
||||
return cors
|
|
@ -5,19 +5,16 @@ local cachestore = require "bunkerweb.cachestore"
|
|||
|
||||
local country = class("country", plugin)
|
||||
|
||||
function country:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "country")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
function country:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "country")
|
||||
-- Instantiate cachestore
|
||||
local use_redis, err = utils.get_variable("USE_REDIS", false)
|
||||
if not use_redis then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
end
|
||||
cachestore:new(use_redis)
|
||||
return true, "success"
|
||||
self.use_redis = use_redis == "yes"
|
||||
self.cachestore = cachestore:new(self.use_redis)
|
||||
end
|
||||
|
||||
function country:access()
|
||||
|
@ -31,8 +28,7 @@ function country:access()
|
|||
if data.result == "ok" then
|
||||
return self:ret(true, "client IP " .. ngx.var.remote_addr .. " is in country cache (not blacklisted, country = " .. data.country .. ")")
|
||||
end
|
||||
return self:ret(true, "client IP " .. ngx.var.remote_addr .. " is in country cache (blacklisted, country = " .. data.country .. ")", utils.get_deny_status()
|
||||
|
||||
return self:ret(true, "client IP " .. ngx.var.remote_addr .. " is in country cache (blacklisted, country = " .. data.country .. ")", utils.get_deny_status())
|
||||
end
|
||||
|
||||
-- Don't go further if IP is not global
|
||||
|
@ -58,14 +54,14 @@ function country:access()
|
|||
for wh_country in self.variables["WHITELIST_COUNTRY"]:gmatch("%S+") do
|
||||
if wh_country == country then
|
||||
local ok, err = self:add_to_cache(ngx.var.remote_addr, country, "ok")
|
||||
if not then
|
||||
if not ok then
|
||||
return self:ret(false, "error while adding item to cache : " .. err)
|
||||
end
|
||||
return self:ret(true, "client IP " .. ngx.var.remote_addr .. " is whitelisted (country = " .. country .. ")")
|
||||
end
|
||||
end
|
||||
local ok, err = self:add_to_cache(ngx.var.remote_addr, country, "ko")
|
||||
if not then
|
||||
if not ok then
|
||||
return self:ret(false, "error while adding item to cache : " .. err)
|
||||
end
|
||||
return self:ret(true, "client IP " .. ngx.var.remote_addr .. " is not whitelisted (country = " .. country .. ")", utils.get_deny_status())
|
||||
|
@ -97,16 +93,16 @@ function country:preread()
|
|||
end
|
||||
|
||||
function country:is_in_cache(ip)
|
||||
local ok, data = cachestore:get("plugin_country_cache_" .. ip)
|
||||
if not ok then then
|
||||
local ok, data = self.cachestore:get("plugin_country_cache_" .. ip)
|
||||
if not ok then
|
||||
return false, data
|
||||
end
|
||||
return true, cjson.decode(data)
|
||||
end
|
||||
|
||||
function country:add_to_cache(ip, country, result)
|
||||
local ok, err = cachestore:set("plugin_country_cache_" .. ip, cjson.encode({country = country, result = result}))
|
||||
if not ok then then
|
||||
local ok, err = self.cachestore:set("plugin_country_cache_" .. ip, cjson.encode({country = country, result = result}))
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
return true
|
||||
|
|
|
@ -7,15 +7,16 @@ local resolver = require "resty.dns.resolver"
|
|||
|
||||
local dnsbl = class("dnsbl", plugin)
|
||||
|
||||
local dnsbl:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "dnsbl")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
function dnsbl:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "dnsbl")
|
||||
-- Instantiate cachestore
|
||||
cachestore:new(use_redis)
|
||||
return true, "success"
|
||||
local use_redis, err = utils.get_variable("USE_REDIS", false)
|
||||
if not use_redis then
|
||||
self.logger:log(ngx.ERR, err)
|
||||
end
|
||||
self.use_redis = use_redis == "yes"
|
||||
self.cachestore = cachestore:new(self.use_redis)
|
||||
end
|
||||
|
||||
function dnsbl:access()
|
||||
|
@ -27,14 +28,14 @@ function dnsbl:access()
|
|||
return self:ret(true, "dnsbl list is empty")
|
||||
end
|
||||
-- Check if IP is in cache
|
||||
local cache, err = self:is_in_cache(ngx.var.remote_addr)
|
||||
if not cache and err ~= "success" then
|
||||
local ok, cached = self:is_in_cache(ngx.var.remote_addr)
|
||||
if not ok then
|
||||
return self:ret(false, "error while checking cache : " .. err)
|
||||
elseif cache then
|
||||
if cache == "ok" then
|
||||
elseif cached then
|
||||
if cached == "ok" then
|
||||
return self:ret(true, "client IP " .. ngx.var.remote_addr .. " is in DNSBL cache (not blacklisted)")
|
||||
end
|
||||
return self:ret(true, "client IP " .. ngx.var.remote_addr .. " is in DNSBL cache (server = " .. cache .. ")", utils.get_deny_status())
|
||||
return self:ret(true, "client IP " .. ngx.var.remote_addr .. " is in DNSBL cache (server = " .. cached .. ")", utils.get_deny_status())
|
||||
end
|
||||
-- Don't go further if IP is not global
|
||||
local is_global, err = utils.ip_is_global(ngx.var.remote_addr)
|
||||
|
@ -74,17 +75,17 @@ function dnsbl:preread()
|
|||
return self:access()
|
||||
end
|
||||
|
||||
function dnsl:is_in_cache(ip)
|
||||
local ok, data = cachestore:get("plugin_dnsbl_" .. ip)
|
||||
if not ok then then
|
||||
function dnsbl:is_in_cache(ip)
|
||||
local ok, data = self.cachestore:get("plugin_dnsbl_" .. ip)
|
||||
if not ok then
|
||||
return false, data
|
||||
end
|
||||
return true, data
|
||||
end
|
||||
|
||||
function dnsbl:add_to_cache(ip, value)
|
||||
local ok, err = cachestore:set("plugin_dnsbl_" .. ip, value)
|
||||
if not ok then then
|
||||
local ok, err = self.cachestore:set("plugin_dnsbl_" .. ip, value)
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
return true
|
||||
|
|
|
@ -28,8 +28,8 @@ location = {{ page }} {
|
|||
root /usr/share/bunkerweb/core/files;
|
||||
content_by_lua_block {
|
||||
local logger = require "bunkerweb.logger"
|
||||
local errors = require "errors.errors"
|
||||
errors:new()
|
||||
local cerrors = require "errors.errors"
|
||||
local errors = cerrors:new()
|
||||
if ngx.status == 200 then
|
||||
errors:render_template(tostring(405))
|
||||
else
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
local class = require "middleclass"
|
||||
local plugin = require "bunkerweb.plugin"
|
||||
local utils = require "bunkerweb.utils"
|
||||
local cachestore = require "bunkerweb.cachestore"
|
||||
local cjson = require "cjson"
|
||||
local template = require "resty.template"
|
||||
|
||||
local errors = class("errors", plugin)
|
||||
|
||||
function errors:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "errors")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
function errors:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "errors")
|
||||
-- Default error texts
|
||||
self.default_errors = {
|
||||
["400"] = {
|
||||
|
@ -64,7 +60,6 @@ function errors:new()
|
|||
text = "The gateway has timed out."
|
||||
}
|
||||
}
|
||||
return true, "success"
|
||||
end
|
||||
|
||||
function errors:render_template(code)
|
||||
|
|
|
@ -1,71 +1,71 @@
|
|||
local class = require "middleclass"
|
||||
local plugin = require "bunkerweb.plugin"
|
||||
local utils = require "bunkerweb.utils"
|
||||
local cjson = require "cjson"
|
||||
local ipmatcher = require "resty.ipmatcher"
|
||||
local class = require "middleclass"
|
||||
local plugin = require "bunkerweb.plugin"
|
||||
local utils = require "bunkerweb.utils"
|
||||
local cachestore = require "bunkerweb.cachestore"
|
||||
local cjson = require "cjson"
|
||||
local ipmatcher = require "resty.ipmatcher"
|
||||
|
||||
local greylist = class("dnsbl", plugin)
|
||||
local greylist = class("greylist", plugin)
|
||||
|
||||
function greylist:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "greylist")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
function greylist:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "greylist")
|
||||
-- Check if redis is enabled
|
||||
local use_redis, err = utils.get_variable("USE_REDIS", false)
|
||||
if not use_redis then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
end
|
||||
self.use_redis = use_redis == "yes"
|
||||
-- Check if init is needed
|
||||
if ngx.get_phase() == "init" then
|
||||
local init_needed, err = utils.has_variable("USE_GREYLIST", "yes")
|
||||
if init_needed == nil then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
end
|
||||
self.init_needed = init_needed
|
||||
-- Decode lists
|
||||
else
|
||||
local lists, err = datastore:get("plugin_greylist_lists")
|
||||
elseif self.variables["USE_GREYLIST"] == "yes" then
|
||||
local lists, err = self.datastore:get("plugin_greylist_lists")
|
||||
if not lists then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
else
|
||||
self.lists = cjson.decode(lists)
|
||||
end
|
||||
self.lists = cjson.decode(lists)
|
||||
end
|
||||
-- Instantiate cachestore
|
||||
cachestore:new(use_redis)
|
||||
return true, "success"
|
||||
self.cachestore = cachestore:new(self.use_redis)
|
||||
end
|
||||
|
||||
function greylist:init()
|
||||
if self.init_needed then
|
||||
-- Read blacklists
|
||||
local greylists = {
|
||||
["IP"] = {},
|
||||
["RDNS"] = {},
|
||||
["ASN"] = {},
|
||||
["USER_AGENT"] = {},
|
||||
["URI"] = {},
|
||||
}
|
||||
local i = 0
|
||||
for kind, _ in pairs(greylists) do
|
||||
local f, err = io.open("/var/cache/bunkerweb/greylist/" .. kind .. ".list", "r")
|
||||
if f then
|
||||
for line in f:lines() do
|
||||
table.insert(greylists[kind], line)
|
||||
i = i + 1
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
-- Load them into datastore
|
||||
local ok, err = datastore:set("plugin_greylist_lists", cjson.encode(greylists))
|
||||
if not ok then
|
||||
return self:ret(false, "can't store greylist list into datastore : " .. err)
|
||||
end
|
||||
return self:ret(true, "successfully loaded " .. tostring(i) .. " bad IP/network/rDNS/ASN/User-Agent/URI")
|
||||
-- Check if init is needed
|
||||
if not self.init_needed then
|
||||
return self:ret(true, "init not needed")
|
||||
end
|
||||
-- Read blacklists
|
||||
local greylists = {
|
||||
["IP"] = {},
|
||||
["RDNS"] = {},
|
||||
["ASN"] = {},
|
||||
["USER_AGENT"] = {},
|
||||
["URI"] = {},
|
||||
}
|
||||
local i = 0
|
||||
for kind, _ in pairs(greylists) do
|
||||
local f, err = io.open("/var/cache/bunkerweb/greylist/" .. kind .. ".list", "r")
|
||||
if f then
|
||||
for line in f:lines() do
|
||||
table.insert(greylists[kind], line)
|
||||
i = i + 1
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
-- Load them into datastore
|
||||
local ok, err = self.datastore:set("plugin_greylist_lists", cjson.encode(greylists))
|
||||
if not ok then
|
||||
return self:ret(false, "can't store greylist list into datastore : " .. err)
|
||||
end
|
||||
return self:ret(true, "successfully loaded " .. tostring(i) .. " bad IP/network/rDNS/ASN/User-Agent/URI")
|
||||
end
|
||||
|
||||
function greylist:access()
|
||||
|
@ -110,7 +110,7 @@ function greylist:access()
|
|||
if greylisted == nil then
|
||||
self.logger:log(ngx.ERR, "error while checking if " .. k .. " is greylisted : " .. err)
|
||||
else
|
||||
local ok, err = self:add_to_cache(v, greylisted or "ok")
|
||||
local ok, err = self:add_to_cache(self:kind_to_ele(k), greylisted or "ok")
|
||||
if not ok then
|
||||
self.logger:log(ngx.ERR, "error while adding element to cache : " .. err)
|
||||
end
|
||||
|
@ -129,13 +129,24 @@ function greylist:preread()
|
|||
return self:access()
|
||||
end
|
||||
|
||||
function greylist:kind_to_ele(kind)
|
||||
if kind == "IP" then
|
||||
return "ip" .. ngx.var.remote_addr
|
||||
elseif kind == "UA" then
|
||||
return "ua" .. ngx.var.http_user_agent
|
||||
elseif kind == "URI" then
|
||||
return "uri" .. ngx.var.uri
|
||||
end
|
||||
end
|
||||
|
||||
function greylist:is_greylisted(kind)
|
||||
if kind == "IP" then
|
||||
return self:is_greylisted_ip()
|
||||
elseif kind == "URI"
|
||||
elseif kind == "URI" then
|
||||
return self:is_greylisted_uri()
|
||||
elseif kind == "UA"
|
||||
elseif kind == "UA" then
|
||||
return self:is_greylisted_ua()
|
||||
end
|
||||
return false, "unknown kind " .. kind
|
||||
end
|
||||
|
||||
|
@ -214,16 +225,16 @@ function greylist:is_greylisted_ua()
|
|||
end
|
||||
|
||||
function greylist:is_in_cache(ele)
|
||||
local ok, data = cachestore:get("plugin_greylist_" .. ele)
|
||||
if not ok then then
|
||||
local ok, data = self.cachestore:get("plugin_greylist_" .. ele)
|
||||
if not ok then
|
||||
return false, data
|
||||
end
|
||||
return true, data
|
||||
end
|
||||
|
||||
function greylist:add_to_cache(ele, value)
|
||||
local ok, err = cachestore:set("plugin_greylist_" .. ele, value)
|
||||
if not ok then then
|
||||
local ok, err = self.cachestore:set("plugin_greylist_" .. ele, value)
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
return true
|
||||
|
|
|
@ -5,12 +5,9 @@ local cjson = require "cjson"
|
|||
|
||||
local letsencrypt = class("letsencrypt", plugin)
|
||||
|
||||
function letsencrypt:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "letsencrypt")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
function letsencrypt:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "letsencrypt")
|
||||
end
|
||||
|
||||
function letsencrypt:access()
|
||||
|
|
|
@ -7,16 +7,13 @@ local cjson = require "cjson"
|
|||
|
||||
local limit = class("limit", plugin)
|
||||
|
||||
function limit:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "limit")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
function limit:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "limit")
|
||||
-- Check if redis is enabled
|
||||
local use_redis, err = utils.get_variable("USE_REDIS", false)
|
||||
if not use_redis then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
end
|
||||
self.use_redis = use_redis == "yes"
|
||||
-- Load rules if needed
|
||||
|
@ -24,9 +21,10 @@ function limit:new()
|
|||
if self.variables["USE_LIMIT_REQ"] == "yes" then
|
||||
-- Get all rules from datastore
|
||||
local limited = false
|
||||
local all_rules, err = datastore:get("plugin_limit_rules")
|
||||
local all_rules, err = self.datastore:get("plugin_limit_rules")
|
||||
if not all_rules then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
return
|
||||
end
|
||||
all_rules = cjson.decode(all_rules)
|
||||
self.rules = {}
|
||||
|
@ -44,7 +42,6 @@ function limit:new()
|
|||
end
|
||||
end
|
||||
end
|
||||
return true, "success"
|
||||
end
|
||||
|
||||
function limit:init()
|
||||
|
@ -77,7 +74,7 @@ function limit:init()
|
|||
end
|
||||
end
|
||||
end
|
||||
local ok, err = datastore:set("plugin_limit_rules", cjson.encode(data))
|
||||
local ok, err = self.datastore:set("plugin_limit_rules", cjson.encode(data))
|
||||
if not ok then
|
||||
return self:ret(false, err)
|
||||
end
|
||||
|
@ -119,11 +116,10 @@ function limit:access()
|
|||
end
|
||||
-- Limit reached
|
||||
if limited then
|
||||
return return self:ret(true, "client IP " .. ngx.var.remote_addr .. " is limited for URL " .. ngx.var.uri .. " (current rate = " .. current_rate .. "r/" .. rate_time .. " and max rate = " .. rate .. ")", ngx.HTTP_TOO_MANY_REQUESTS)
|
||||
return self:ret(true, "client IP " .. ngx.var.remote_addr .. " is limited for URL " .. ngx.var.uri .. " (current rate = " .. current_rate .. "r/" .. rate_time .. " and max rate = " .. rate .. ")", ngx.HTTP_TOO_MANY_REQUESTS)
|
||||
end
|
||||
-- Limit not reached
|
||||
return self:ret(true, "client IP " .. ngx.var.remote_addr .. " is not limited for URL " .. ngx.var.uri .. " (current rate = " .. current_rate .. "r/" .. rate_time .. " and max rate = " .. rate .. ")")
|
||||
end
|
||||
return self:ret(true, "client IP " .. ngx.var.remote_addr .. " is not limited for URL " .. ngx.var.uri .. " (current rate = " .. current_rate .. "r/" .. rate_time .. " and max rate = " .. rate .. ")")
|
||||
end
|
||||
|
||||
function limit:limit_req(rate_max, rate_time)
|
||||
|
@ -136,7 +132,7 @@ function limit:limit_req(rate_max, rate_time)
|
|||
else
|
||||
timestamps = redis_timestamps
|
||||
-- Save the new timestamps
|
||||
local ok, err = datastore:set("plugin_limit_cache_" .. ngx.var.server_name .. ngx.var.remote_addr .. ngx.var.uri, cjson.encode(timestamps), delay)
|
||||
local ok, err = self.datastore:set("plugin_limit_cache_" .. ngx.var.server_name .. ngx.var.remote_addr .. ngx.var.uri, cjson.encode(timestamps), delay)
|
||||
if not ok then
|
||||
return nil, "can't update timestamps : " .. err
|
||||
end
|
||||
|
@ -158,7 +154,7 @@ end
|
|||
|
||||
function limit:limit_req_local(rate_max, rate_time)
|
||||
-- Get timestamps
|
||||
local timestamps, err = datastore:get("plugin_limit_cache_" .. ngx.var.server_name .. ngx.var.remote_addr .. ngx.var.uri)
|
||||
local timestamps, err = self.datastore:get("plugin_limit_cache_" .. ngx.var.server_name .. ngx.var.remote_addr .. ngx.var.uri)
|
||||
if not timestamps and err ~= "not found" then
|
||||
return nil, err
|
||||
elseif err == "not found" then
|
||||
|
@ -169,7 +165,7 @@ function limit:limit_req_local(rate_max, rate_time)
|
|||
local updated, new_timestamps, delay = self:limit_req_timestamps(rate_max, rate_time, timestamps)
|
||||
-- Save new timestamps if needed
|
||||
if updated then
|
||||
local ok, err = datastore:set("plugin_limit_cache_" .. ngx.var.server_name .. ngx.var.remote_addr .. ngx.var.uri, cjson.encode(timestamps), delay)
|
||||
local ok, err = self.datastore:set("plugin_limit_cache_" .. ngx.var.server_name .. ngx.var.remote_addr .. ngx.var.uri, cjson.encode(timestamps), delay)
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
|
|
|
@ -6,13 +6,9 @@ local clusterstore = require "bunkerweb.clusterstore"
|
|||
|
||||
local redis = class("redis", plugin)
|
||||
|
||||
function redis:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "redis")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
return true, "success"
|
||||
function redis:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "redis")
|
||||
end
|
||||
|
||||
function redis:init()
|
||||
|
|
|
@ -5,19 +5,16 @@ local cachestore = require "bunkerweb.cachestore"
|
|||
|
||||
local reversescan = class("reversescan", plugin)
|
||||
|
||||
function reversescan:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "reversescan")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
function reversescan:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "reversescan")
|
||||
-- Instantiate cachestore
|
||||
local use_redis, err = utils.get_variable("USE_REDIS", false)
|
||||
if not use_redis then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
end
|
||||
cachestore:new(use_redis)
|
||||
return true, "success"
|
||||
self.use_redis = use_redis == "yes"
|
||||
self.cachestore = cachestore:new(self.use_redis)
|
||||
end
|
||||
|
||||
function reversescan:access()
|
||||
|
@ -64,16 +61,16 @@ function reversescan:scan(ip, port, timeout)
|
|||
end
|
||||
|
||||
function reversescan:is_in_cache(ip_port)
|
||||
local ok, data = cachestore:get("plugin_reversescan_cache_" .. ip_port)
|
||||
if not ok then then
|
||||
local ok, data = self.cachestore:get("plugin_reversescan_cache_" .. ip_port)
|
||||
if not ok then
|
||||
return false, data
|
||||
end
|
||||
return true, data
|
||||
end
|
||||
|
||||
function reversescan:add_to_cache(ip_port, value)
|
||||
local ok, err = cachestore:set("plugin_reversescan_cache_" .. ip_port, value)
|
||||
if not ok then then
|
||||
local ok, err = self.cachestore:set("plugin_reversescan_cache_" .. ip_port, value)
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
return true
|
||||
|
|
|
@ -1,22 +1,18 @@
|
|||
local _M = {}
|
||||
_M.__index = _M
|
||||
|
||||
local utils = require "utils"
|
||||
local class = require "middleclass"
|
||||
local plugin = require "bunkerweb.plugin"
|
||||
local utils = require "bunkerweb.utils"
|
||||
local session = require "resty.session"
|
||||
|
||||
function _M.new()
|
||||
local self = setmetatable({}, _M)
|
||||
return self, nil
|
||||
local sessions = class("sessions", plugin)
|
||||
|
||||
function sessions:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "sessions")
|
||||
end
|
||||
|
||||
function _M:init()
|
||||
-- Get vars
|
||||
local vars = {
|
||||
["SESSIONS_SECRET"] = "",
|
||||
["SESSIONS_NAME"] = "",
|
||||
["SESSIONS_IDLING_TIMEOUT"] = "",
|
||||
["SESSIONS_ROLLING_TIMEOUT"] = "",
|
||||
["SESSIONS_ABSOLUTE_TIMEOUT"] = "",
|
||||
function sessions:init()
|
||||
-- Get redis vars
|
||||
local redis_vars = {
|
||||
["USE_REDIS"] = "",
|
||||
["REDIS_HOST"] = "",
|
||||
["REDIS_PORT"] = "",
|
||||
|
@ -25,46 +21,46 @@ function _M:init()
|
|||
["REDIS_KEEPALIVE_IDLE"] = "",
|
||||
["REDIS_KEEPALIVE_POOL"] = ""
|
||||
}
|
||||
for k, v in pairs(vars) do
|
||||
for k, v in pairs(redis_vars) do
|
||||
local var, err = utils.get_variable(k, false)
|
||||
if var == nil then
|
||||
return false, "can't get " .. k .. " variable : " .. err
|
||||
return self:ret(false, "can't get " .. k .. " variable : " .. err)
|
||||
end
|
||||
end
|
||||
-- Init configuration
|
||||
local config = {
|
||||
secret = vars["SESSIONS_SECRET"],
|
||||
cookie_name = vars["SESSIONS_NAME"],
|
||||
idling_timeout = tonumber(vars["SESSIONS_IDLING_TIMEOUT"]),
|
||||
rolling_timeout = tonumber(vars["SESSIONS_ROLLING_TIMEOUT"]),
|
||||
absolute_timeout = tonumber(vars["SESSIONS_ABSOLUTE_TIMEOUT"])
|
||||
secret = self.variables["SESSIONS_SECRET"],
|
||||
cookie_name = self.variables["SESSIONS_NAME"],
|
||||
idling_timeout = tonumber(self.variables["SESSIONS_IDLING_TIMEOUT"]),
|
||||
rolling_timeout = tonumber(self.variables["SESSIONS_ROLLING_TIMEOUT"]),
|
||||
absolute_timeout = tonumber(self.variables["SESSIONS_ABSOLUTE_TIMEOUT"])
|
||||
}
|
||||
if vars["SESSIONS_SECRET"] == "random" then
|
||||
if self.variables["SESSIONS_SECRET"] == "random" then
|
||||
config.secret = utils.rand(16)
|
||||
end
|
||||
if vars["SESSIONS_NAME"] == "random" then
|
||||
if self.variables["SESSIONS_NAME"] == "random" then
|
||||
config.cookie_name = utils.rand(16)
|
||||
end
|
||||
if vars["USE_REDIS"] == "no" then
|
||||
if redis_vars["USE_REDIS"] ~= "yes" then
|
||||
config.storage = "cookie"
|
||||
else
|
||||
config.storage = "redis"
|
||||
config.redis = {
|
||||
prefix = "sessions_",
|
||||
connect_timeout = tonumber(vars["REDIS_TIMEOUT"]),
|
||||
send_timeout = tonumber(vars["REDIS_TIMEOUT"]),
|
||||
read_timeout = tonumber(vars["REDIS_TIMEOUT"]),
|
||||
keepalive_timeout = tonumber(vars["REDIS_KEEPALIVE_IDLE"]),
|
||||
connect_timeout = tonumber(redis_vars["REDIS_TIMEOUT"]),
|
||||
send_timeout = tonumber(redis_vars["REDIS_TIMEOUT"]),
|
||||
read_timeout = tonumber(redis_vars["REDIS_TIMEOUT"]),
|
||||
keepalive_timeout = tonumber(redis_vars["REDIS_KEEPALIVE_IDLE"]),
|
||||
pool = "bw",
|
||||
pool_size = tonumber(vars["REDIS_KEEPALIVE_POOL"]),
|
||||
ssl = vars["REDIS_SSL"] == "yes",
|
||||
host = vars["REDIS_HOST"],
|
||||
port = tonumber(vars["REDIS_HOST"]),
|
||||
database = tonumber(vars["REDIS_DATABASE"])
|
||||
pool_size = tonumber(redis_vars["REDIS_KEEPALIVE_POOL"]),
|
||||
ssl = redis_vars["REDIS_SSL"] == "yes",
|
||||
host = redis_vars["REDIS_HOST"],
|
||||
port = tonumber(redis_vars["REDIS_HOST"]),
|
||||
database = tonumber(redis_vars["REDIS_DATABASE"])
|
||||
}
|
||||
end
|
||||
session.init(config)
|
||||
return true, "sessions init successful"
|
||||
return self:ret(true, "sessions init successful")
|
||||
end
|
||||
|
||||
return _M
|
||||
return sessions
|
|
@ -9,66 +9,65 @@ local env = require "resty.env"
|
|||
|
||||
local whitelist = class("whitelist", plugin)
|
||||
|
||||
function whitelist:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "whitelist")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
function whitelist:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "whitelist")
|
||||
-- Check if redis is enabled
|
||||
local use_redis, err = utils.get_variable("USE_REDIS", false)
|
||||
if not use_redis then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
end
|
||||
self.use_redis = use_redis == "yes"
|
||||
-- Check if init is needed
|
||||
if ngx.get_phase() == "init" then
|
||||
local init_needed, err = utils.has_variable("USE_WHITELIST", "yes")
|
||||
if init_needed == nil then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
end
|
||||
self.init_needed = init_needed
|
||||
-- Decode lists
|
||||
else
|
||||
local lists, err = datastore:get("plugin_whitelist_lists")
|
||||
local lists, err = self.datastore:get("plugin_whitelist_lists")
|
||||
if not lists then
|
||||
return false, err
|
||||
self.logger:log(ngx.ERR, err)
|
||||
else
|
||||
self.lists = cjson.decode(lists)
|
||||
end
|
||||
self.lists = cjson.decode(lists)
|
||||
end
|
||||
-- Instantiate cachestore
|
||||
cachestore:new(use_redis)
|
||||
return true, "success"
|
||||
self.cachestore = cachestore:new(self.use_redis)
|
||||
end
|
||||
|
||||
function whitelist:init()
|
||||
if self.init_needed then
|
||||
-- Read whitelists
|
||||
local whitelists = {
|
||||
["IP"] = {},
|
||||
["RDNS"] = {},
|
||||
["ASN"] = {},
|
||||
["USER_AGENT"] = {},
|
||||
["URI"] = {}
|
||||
}
|
||||
local i = 0
|
||||
for kind, _ in pairs(whitelists) do
|
||||
local f, err = io.open("/var/cache/bunkerweb/whitelist/" .. kind .. ".list", "r")
|
||||
if f then
|
||||
for line in f:lines() do
|
||||
table.insert(whitelists[kind], line)
|
||||
i = i + 1
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
-- Load them into datastore
|
||||
local ok, err = datastore:set("plugin_whitelist_lists", cjson.encode(whitelists))
|
||||
if not ok then
|
||||
return self:ret(false, "can't store whitelist list into datastore : " .. err)
|
||||
end
|
||||
return self:ret(true, "successfully loaded " .. tostring(i) .. " IP/network/rDNS/ASN/User-Agent/URI")
|
||||
-- Check if init is needed
|
||||
if not self.init_needed then
|
||||
return self:ret(true, "init not needed")
|
||||
end
|
||||
-- Read whitelists
|
||||
local whitelists = {
|
||||
["IP"] = {},
|
||||
["RDNS"] = {},
|
||||
["ASN"] = {},
|
||||
["USER_AGENT"] = {},
|
||||
["URI"] = {}
|
||||
}
|
||||
local i = 0
|
||||
for kind, _ in pairs(whitelists) do
|
||||
local f, err = io.open("/var/cache/bunkerweb/whitelist/" .. kind .. ".list", "r")
|
||||
if f then
|
||||
for line in f:lines() do
|
||||
table.insert(whitelists[kind], line)
|
||||
i = i + 1
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
-- Load them into datastore
|
||||
local ok, err = self.datastore:set("plugin_whitelist_lists", cjson.encode(whitelists))
|
||||
if not ok then
|
||||
return self:ret(false, "can't store whitelist list into datastore : " .. err)
|
||||
end
|
||||
return self:ret(true, "successfully loaded " .. tostring(i) .. " IP/network/rDNS/ASN/User-Agent/URI")
|
||||
end
|
||||
|
||||
function whitelist:set()
|
||||
|
@ -112,7 +111,7 @@ function whitelist:access()
|
|||
if ok == nil then
|
||||
self.logger:log(ngx.ERR, "error while checking if " .. k .. " is whitelisted : " .. err)
|
||||
else
|
||||
local ok, err = self:add_to_cache(v, whitelisted)
|
||||
local ok, err = self:add_to_cache(self:kind_to_ele(k), whitelisted)
|
||||
if not ok then
|
||||
self.logger:log(ngx.ERR, "error while adding element to cache : " .. err)
|
||||
end
|
||||
|
@ -132,6 +131,16 @@ function whitelist:preread()
|
|||
return self:access()
|
||||
end
|
||||
|
||||
function whitelist:kind_to_ele(kind)
|
||||
if kind == "IP" then
|
||||
return "ip" .. ngx.var.remote_addr
|
||||
elseif kind == "UA" then
|
||||
return "ua" .. ngx.var.http_user_agent
|
||||
elseif kind == "URI" then
|
||||
return "uri" .. ngx.var.uri
|
||||
end
|
||||
end
|
||||
|
||||
function whitelist:check_cache()
|
||||
-- Check the caches
|
||||
local checks = {
|
||||
|
@ -168,16 +177,16 @@ function whitelist:check_cache()
|
|||
end
|
||||
|
||||
function whitelist:is_in_cache(ele)
|
||||
local ok, data = cachestore:get("plugin_whitelist_" .. ele)
|
||||
if not ok then then
|
||||
local ok, data = self.cachestore:get("plugin_whitelist_" .. ele)
|
||||
if not ok then
|
||||
return false, data
|
||||
end
|
||||
return true, data
|
||||
end
|
||||
|
||||
function whitelist:add_to_cache(ele, value)
|
||||
local ok, err = cachestore:set("plugin_whitelist_" .. ele, value)
|
||||
if not ok then then
|
||||
local ok, err = self.cachestore:set("plugin_whitelist_" .. ele, value)
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
return true
|
||||
|
@ -186,10 +195,11 @@ end
|
|||
function whitelist:is_whitelisted(kind)
|
||||
if kind == "IP" then
|
||||
return self:is_whitelisted_ip()
|
||||
elseif kind == "URI"
|
||||
elseif kind == "URI" then
|
||||
return self:is_whitelisted_uri()
|
||||
elseif kind == "UA"
|
||||
elseif kind == "UA" then
|
||||
return self:is_whitelisted_ua()
|
||||
end
|
||||
return false, "unknown kind " .. kind
|
||||
end
|
||||
|
||||
|
|
|
@ -254,14 +254,30 @@ git_secure_clone "https://github.com/bungle/lua-resty-template.git" "c08c6bc9e27
|
|||
echo "ℹ️ Downloading lua-resty-lock"
|
||||
git_secure_clone "https://github.com/openresty/lua-resty-lock.git" "9dc550e56b6f3b1a2f1a31bb270a91813b5b6861"
|
||||
|
||||
# lua-pack v2.0.0
|
||||
echo "ℹ️ Downloading lua-pack"
|
||||
dopatch="no"
|
||||
if [ ! -d "deps/src/lua-pack" ] ; then
|
||||
dopatch="yes"
|
||||
fi
|
||||
git_secure_clone "https://github.com/Kong/lua-pack.git" "495bf30606b9744140258df349862981e3ee7820"
|
||||
if [ "$dopatch" = "yes" ] ; then
|
||||
do_and_check_cmd cp deps/misc/lua-pack.Makefile deps/src/lua-pack/Makefile
|
||||
fi
|
||||
|
||||
# lua-resty-openssl v0.8.21
|
||||
echo "ℹ️ Downloading lua-resty-openssl"
|
||||
git_secure_clone "https://github.com/fffonion/lua-resty-openssl.git" "15bc59b97feb5acf25fbdd9426cf73870cf7c838"
|
||||
|
||||
# ModSecurity v3.0.9
|
||||
echo "ℹ️ Downloading ModSecurity"
|
||||
dopatch="no"
|
||||
if [ ! -d "deps/src/ModSecurity" ] ; then
|
||||
dopatch="yes"
|
||||
dopatch="yes"
|
||||
fi
|
||||
git_secure_clone "https://github.com/SpiderLabs/ModSecurity.git" "205dac0e8c675182f96b5c2fb06be7d1cf7af2b2"
|
||||
if [ "$dopatch" = "yes" ] ; then
|
||||
do_and_check_cmd patch deps/src/ModSecurity/configure.ac deps/misc/modsecurity.patch
|
||||
do_and_check_cmd patch deps/src/ModSecurity/configure.ac deps/misc/modsecurity.patch
|
||||
fi
|
||||
|
||||
# libinjection v3.10.0+
|
||||
|
|
|
@ -135,6 +135,14 @@ do_and_check_cmd cp -r /tmp/bunkerweb/deps/src/lua-resty-template/lib/resty/* /u
|
|||
echo "ℹ️ Installing lua-resty-lock"
|
||||
CHANGE_DIR="/tmp/bunkerweb/deps/src/lua-resty-lock" do_and_check_cmd make PREFIX=/usr/share/bunkerweb/deps LUA_LIB_DIR=/usr/share/bunkerweb/deps/lib/lua install
|
||||
|
||||
# Installing lua-pack
|
||||
echo "ℹ️ Installing lua-pack"
|
||||
CHANGE_DIR="/tmp/bunkerweb/deps/src/lua-pack" do_and_check_cmd make INST_LIBDIR=/usr/share/bunkerweb/deps/lib/lua LUA_LIBDIR=-L/usr/share/bunkerweb/deps/lib LUA_INCDIR=-I/usr/share/bunkerweb/deps/include install
|
||||
|
||||
# Installing lua-resty-openssl
|
||||
echo "ℹ️ Installing lua-resty-openssl"
|
||||
CHANGE_DIR="/tmp/bunkerweb/deps/src/lua-resty-openssl" do_and_check_cmd make LUA_LIB_DIR=/usr/share/bunkerweb/deps/lib/lua install
|
||||
|
||||
# Compile dynamic modules
|
||||
echo "ℹ️ Compiling and installing dynamic modules"
|
||||
CONFARGS="$(nginx -V 2>&1 | sed -n -e 's/^.*arguments: //p')"
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
LUA ?= lua5.1
|
||||
LUA_LIBDIR ?= $(shell pkg-config $(LUA) --libs)
|
||||
LUA_INCDIR ?= $(shell pkg-config $(LUA) --cflags)
|
||||
|
||||
LIBFLAG ?= -shared
|
||||
CFLAGS ?= -std=c99 -O2 -Wall
|
||||
|
||||
.PHONY: all clean install
|
||||
|
||||
all: lua_pack.so
|
||||
|
||||
lua_pack.so: lua_pack.o
|
||||
$(CC) $(LIBFLAG) $(LUA_LIBDIR) $< -o $@
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) -fPIC $(LUA_INCDIR) $< -o $@
|
||||
|
||||
install: lua_pack.so
|
||||
cp lua_pack.so $(INST_LIBDIR)
|
||||
|
||||
clean:
|
||||
rm -f *.so *.o *.rock
|
||||
|
||||
# eof
|
|
@ -0,0 +1,19 @@
|
|||
--- /dev/null
|
||||
+++ /dev/null
|
||||
@@ -322,12 +322,12 @@
|
||||
|
||||
# Decide if we want to build the tests or not.
|
||||
-buildTestUtilities=false
|
||||
-if test "x$YAJL_FOUND" = "x1"; then
|
||||
+# buildTestUtilities=false
|
||||
+# if test "x$YAJL_FOUND" = "x1"; then
|
||||
# Regression tests will not be able to run without the logging support.
|
||||
# But we still have the unit tests.
|
||||
# if test "$debugLogs" = "true"; then
|
||||
- buildTestUtilities=true
|
||||
+# buildTestUtilities=true
|
||||
# fi
|
||||
-fi
|
||||
+# fi
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Mashape, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,24 @@
|
|||
LUA ?= lua5.1
|
||||
LUA_LIBDIR ?= $(shell pkg-config $(LUA) --libs)
|
||||
LUA_INCDIR ?= $(shell pkg-config $(LUA) --cflags)
|
||||
|
||||
LIBFLAG ?= -shared
|
||||
CFLAGS ?= -std=c99 -O2 -Wall
|
||||
|
||||
.PHONY: all clean install
|
||||
|
||||
all: lua_pack.so
|
||||
|
||||
lua_pack.so: lua_pack.o
|
||||
$(CC) $(LIBFLAG) $(LUA_LIBDIR) $< -o $@
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) -fPIC $(LUA_INCDIR) $< -o $@
|
||||
|
||||
install: lua_pack.so
|
||||
cp lua_pack.so $(INST_LIBDIR)
|
||||
|
||||
clean:
|
||||
rm -f *.so *.o *.rock
|
||||
|
||||
# eof
|
|
@ -0,0 +1,35 @@
|
|||
This library is extended from `lpack` library on Luarocks to support Hexdecimal data too.
|
||||
|
||||
This is a simple Lua library for packing and unpacking binary data.
|
||||
The library provides two functions: `pack` and `unpack`.
|
||||
|
||||
`pack` is called as follows: `pack(F,x1,x2,...)`, where `F` is a string describing
|
||||
how the values `x1`, `x2`, ... are to be interpreted and formatted. Each letter
|
||||
in the format string `F` consumes one of the given values. Only values of type
|
||||
number or string are accepted. `pack` returns a (binary) string containing the
|
||||
values packed as described in `F`. The letter codes understood by pack are listed
|
||||
in lpack.c (they are inspired by Perl's codes but are not the same). Numbers
|
||||
following letter codes in `F` indicate repetitions.
|
||||
|
||||
`unpack` is called as follows: `unpack(s,F,[init])`, where `s` is a (binary) string
|
||||
containing data packed as if by `pack`, `F` is a format string describing what is
|
||||
to be read from `s`, and the optional `init` marks where in `s` to begin reading the
|
||||
values. `unpack` returns one value per letter in `F` until `F` or `s` is exhausted
|
||||
(the letters codes are the same as for `pack`, except that numbers following ``A'`
|
||||
are interpreted as the number of characters to read into the string, not as
|
||||
repetitions).
|
||||
|
||||
The first value returned by `unpack` is the next unread position in `s`, which can
|
||||
be used as the init position in a subsequent call to `unpack`. This allows you to
|
||||
unpack values in a loop or in several steps. If the position returned by `unpack`
|
||||
is beyond the end of `s`, then `s` has been exhausted; any calls to `unpack` starting
|
||||
beyond the end of `s` will always return `nil` values.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
```
|
||||
pack library:
|
||||
pack(f,...) unpack(s,f,[init])
|
||||
```
|
||||
|
||||
-------------------------------------------------------------------------------
|
|
@ -0,0 +1,25 @@
|
|||
package="lua_pack"
|
||||
version="2.0.0-0"
|
||||
source = {
|
||||
url = "git://github.com/mashape/lua-pack",
|
||||
tag = "2.0.0"
|
||||
}
|
||||
description = {
|
||||
summary = "This is a simple Lua library for packing and unpacking binary data",
|
||||
detailed = [[
|
||||
This is a simple Lua library for packing and unpacking binary data.
|
||||
]],
|
||||
homepage = "https://github.com/mashape/lua-pack",
|
||||
license = "MIT"
|
||||
}
|
||||
dependencies = {
|
||||
"lua >= 5.1, < 5.3"
|
||||
}
|
||||
build = {
|
||||
type = "builtin",
|
||||
modules = {
|
||||
["lua_pack"] = {
|
||||
sources = { "lua_pack.c" },
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,396 @@
|
|||
/***
|
||||
This is a simple Lua library for packing and unpacking binary data.
|
||||
@license MIT
|
||||
@module lua_pack
|
||||
*/
|
||||
#define OP_ZSTRING 'z' /* zero-terminated string */
|
||||
#define OP_BSTRING 'p' /* string preceded by length byte */
|
||||
#define OP_WSTRING 'P' /* string preceded by length word */
|
||||
#define OP_SSTRING 'a' /* string preceded by length size_t */
|
||||
#define OP_STRING 'A' /* string */
|
||||
#define OP_FLOAT 'f' /* float */
|
||||
#define OP_DOUBLE 'd' /* double */
|
||||
#define OP_NUMBER 'n' /* Lua number */
|
||||
#define OP_CHAR 'c' /* char */
|
||||
#define OP_BYTE 'C' /* byte = unsigned char */
|
||||
#define OP_SHORT 's' /* short */
|
||||
#define OP_USHORT 'S' /* unsigned short */
|
||||
#define OP_INT 'i' /* int */
|
||||
#define OP_UINT 'I' /* unsigned int */
|
||||
#define OP_LONG 'l' /* long */
|
||||
#define OP_ULONG 'L' /* unsigned long */
|
||||
#define OP_LITTLEENDIAN '<' /* little endian */
|
||||
#define OP_BIGENDIAN '>' /* big endian */
|
||||
#define OP_NATIVE '=' /* native endian */
|
||||
#define OP_BINMSB 'B'
|
||||
#define OP_HEX 'X'
|
||||
#define OP_NULL 'x'
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
static void badcode(lua_State *L, int c)
|
||||
{
|
||||
char s[]="bad code `?'";
|
||||
s[sizeof(s)-3]=c;
|
||||
luaL_argerror(L,1,s);
|
||||
}
|
||||
|
||||
static int doendian(int c)
|
||||
{
|
||||
int x=1;
|
||||
int e=*(char*)&x;
|
||||
if (c==OP_LITTLEENDIAN) return !e;
|
||||
if (c==OP_BIGENDIAN) return e;
|
||||
if (c==OP_NATIVE) return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void doswap(int swap, void *p, size_t n)
|
||||
{
|
||||
if (swap)
|
||||
{
|
||||
char *a=p;
|
||||
int i,j;
|
||||
for (i=0, j=n-1, n=n/2; n--; i++, j--)
|
||||
{
|
||||
char t=a[i]; a[i]=a[j]; a[j]=t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define UNPACKNUMBER(OP,T) \
|
||||
case OP: \
|
||||
{ \
|
||||
T a; \
|
||||
int m=sizeof(a); \
|
||||
if (i+m>len) goto done; \
|
||||
memcpy(&a,s+i,m); \
|
||||
i+=m; \
|
||||
doswap(swap,&a,m); \
|
||||
lua_pushnumber(L,(lua_Number)a); \
|
||||
++n; \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define UNPACKSTRING(OP,T) \
|
||||
case OP: \
|
||||
{ \
|
||||
T l; \
|
||||
int m=sizeof(l); \
|
||||
if (i+m>len) goto done; \
|
||||
memcpy(&l,s+i,m); \
|
||||
doswap(swap,&l,m); \
|
||||
if (i+m+l>len) goto done; \
|
||||
i+=m; \
|
||||
lua_pushlstring(L,s+i,l); \
|
||||
i+=l; \
|
||||
++n; \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define HEXDIGITS(DIG) \
|
||||
"0123456789ABCDEF"[DIG]
|
||||
|
||||
static int l_unpack(lua_State *L) /** unpack(s,f,[init]) */
|
||||
{
|
||||
size_t len;
|
||||
const char *s=luaL_checklstring(L,1,&len);
|
||||
const char *f=luaL_checkstring(L,2);
|
||||
int i=luaL_optnumber(L,3,1)-1;
|
||||
int n=0;
|
||||
int swap=0;
|
||||
lua_pushnil(L);
|
||||
while (*f)
|
||||
{
|
||||
int c=*f++;
|
||||
int N=1;
|
||||
if (isdigit(*f))
|
||||
{
|
||||
N=0;
|
||||
while (isdigit(*f)) N=10*N+(*f++)-'0';
|
||||
if (N==0 && c==OP_STRING) { lua_pushliteral(L,""); ++n; }
|
||||
}
|
||||
while (N--) switch (c)
|
||||
{
|
||||
case OP_LITTLEENDIAN:
|
||||
case OP_BIGENDIAN:
|
||||
case OP_NATIVE:
|
||||
{
|
||||
swap=doendian(c);
|
||||
N=0;
|
||||
break;
|
||||
}
|
||||
case OP_STRING:
|
||||
{
|
||||
++N;
|
||||
if (i+N>len) goto done;
|
||||
lua_pushlstring(L,s+i,N);
|
||||
i+=N;
|
||||
++n;
|
||||
N=0;
|
||||
break;
|
||||
}
|
||||
case OP_ZSTRING:
|
||||
{
|
||||
size_t l;
|
||||
if (i>=len) goto done;
|
||||
l=strlen(s+i);
|
||||
lua_pushlstring(L,s+i,l);
|
||||
i+=l+1;
|
||||
++n;
|
||||
break;
|
||||
}
|
||||
UNPACKSTRING(OP_BSTRING, unsigned char)
|
||||
UNPACKSTRING(OP_WSTRING, unsigned short)
|
||||
UNPACKSTRING(OP_SSTRING, size_t)
|
||||
UNPACKNUMBER(OP_NUMBER, lua_Number)
|
||||
UNPACKNUMBER(OP_DOUBLE, double)
|
||||
UNPACKNUMBER(OP_FLOAT, float)
|
||||
UNPACKNUMBER(OP_CHAR, char)
|
||||
UNPACKNUMBER(OP_BYTE, unsigned char)
|
||||
UNPACKNUMBER(OP_SHORT, short)
|
||||
UNPACKNUMBER(OP_USHORT, unsigned short)
|
||||
UNPACKNUMBER(OP_INT, int)
|
||||
UNPACKNUMBER(OP_UINT, unsigned int)
|
||||
UNPACKNUMBER(OP_LONG, long)
|
||||
UNPACKNUMBER(OP_ULONG, unsigned long)
|
||||
case OP_BINMSB:
|
||||
{
|
||||
luaL_Buffer buf;
|
||||
luaL_buffinit(L,&buf);
|
||||
unsigned char sbyte = 0x80;
|
||||
N++;
|
||||
if (i+N > len) goto done;
|
||||
unsigned int ii;
|
||||
for (ii = i; ii < i+N; ii++) {
|
||||
sbyte = 0x80;
|
||||
int ij;
|
||||
for (ij = 0; ij < 8; ij++) {
|
||||
if (s[ii] & sbyte) {
|
||||
luaL_addlstring(&buf, "1", 1);
|
||||
} else {
|
||||
luaL_addlstring(&buf, "0", 1);
|
||||
}
|
||||
sbyte = sbyte >> 1;
|
||||
}
|
||||
}
|
||||
luaL_pushresult(&buf);
|
||||
n++;
|
||||
i += N;
|
||||
N = 0;
|
||||
break;
|
||||
}
|
||||
case OP_HEX:
|
||||
{
|
||||
luaL_Buffer buf;
|
||||
char hdigit = '0';
|
||||
int val = 0;
|
||||
luaL_buffinit(L,&buf);
|
||||
N++;
|
||||
if (i+N > len) goto done;
|
||||
unsigned int ii;
|
||||
for (ii = i; ii < i+N; ii++) {
|
||||
val = s[ii] & 0xF0;
|
||||
val = val >> 4;
|
||||
hdigit = HEXDIGITS(val);
|
||||
luaL_addlstring(&buf, &hdigit, 1);
|
||||
|
||||
val = s[ii] & 0x0F;
|
||||
hdigit = HEXDIGITS(val);
|
||||
luaL_addlstring(&buf, &hdigit, 1);
|
||||
}
|
||||
luaL_pushresult(&buf);
|
||||
n++;
|
||||
i += N;
|
||||
N = 0;
|
||||
break;
|
||||
}
|
||||
case OP_NULL:
|
||||
{
|
||||
i+= N + 1;
|
||||
N = 0;
|
||||
break;
|
||||
}
|
||||
case ' ': case ',':
|
||||
break;
|
||||
default:
|
||||
badcode(L,c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
done:
|
||||
lua_pushnumber(L,i+1);
|
||||
lua_replace(L,-n-2);
|
||||
return n+1;
|
||||
}
|
||||
|
||||
#define PACKNUMBER(OP,T) \
|
||||
case OP: \
|
||||
{ \
|
||||
T a=(T)luaL_checknumber(L,i++); \
|
||||
doswap(swap,&a,sizeof(a)); \
|
||||
luaL_addlstring(&b,(void*)&a,sizeof(a)); \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define PACKSTRING(OP,T) \
|
||||
case OP: \
|
||||
{ \
|
||||
size_t l; \
|
||||
const char *a=luaL_checklstring(L,i++,&l); \
|
||||
T ll=(T)l; \
|
||||
doswap(swap,&ll,sizeof(ll)); \
|
||||
luaL_addlstring(&b,(void*)&ll,sizeof(ll)); \
|
||||
luaL_addlstring(&b,a,l); \
|
||||
break; \
|
||||
}
|
||||
|
||||
static int l_pack(lua_State *L) /** pack(f,...) */
|
||||
{
|
||||
int i=2;
|
||||
const char *f=luaL_checkstring(L,1);
|
||||
int swap=0;
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L,&b);
|
||||
while (*f)
|
||||
{
|
||||
int c=*f++;
|
||||
int N=1;
|
||||
if (isdigit(*f))
|
||||
{
|
||||
N=0;
|
||||
while (isdigit(*f)) N=10*N+(*f++)-'0';
|
||||
}
|
||||
while (N--) switch (c)
|
||||
{
|
||||
case OP_LITTLEENDIAN:
|
||||
case OP_BIGENDIAN:
|
||||
case OP_NATIVE:
|
||||
{
|
||||
swap=doendian(c);
|
||||
N=0;
|
||||
break;
|
||||
}
|
||||
case OP_STRING:
|
||||
case OP_ZSTRING:
|
||||
{
|
||||
size_t l;
|
||||
const char *a=luaL_checklstring(L,i++,&l);
|
||||
luaL_addlstring(&b,a,l+(c==OP_ZSTRING));
|
||||
break;
|
||||
}
|
||||
PACKSTRING(OP_BSTRING, unsigned char)
|
||||
PACKSTRING(OP_WSTRING, unsigned short)
|
||||
PACKSTRING(OP_SSTRING, size_t)
|
||||
PACKNUMBER(OP_NUMBER, lua_Number)
|
||||
PACKNUMBER(OP_DOUBLE, double)
|
||||
PACKNUMBER(OP_FLOAT, float)
|
||||
PACKNUMBER(OP_CHAR, char)
|
||||
PACKNUMBER(OP_BYTE, unsigned char)
|
||||
PACKNUMBER(OP_SHORT, short)
|
||||
PACKNUMBER(OP_USHORT, unsigned short)
|
||||
PACKNUMBER(OP_INT, int)
|
||||
PACKNUMBER(OP_UINT, unsigned int)
|
||||
PACKNUMBER(OP_LONG, long)
|
||||
PACKNUMBER(OP_ULONG, unsigned long)
|
||||
case OP_BINMSB:
|
||||
{
|
||||
unsigned char sbyte = 0;
|
||||
size_t l;
|
||||
unsigned int ii = 0, ia = 0;
|
||||
const char *a = luaL_checklstring(L, i++, &l);
|
||||
for (ia = 0; ia < l; ia+= 8) {
|
||||
sbyte = 0;
|
||||
for (ii = 0; ii+ia < l && ii < 8; ii++) {
|
||||
sbyte = sbyte << 1;
|
||||
if (a[ii+ia] != '0') {
|
||||
sbyte++;
|
||||
}
|
||||
}
|
||||
for (; ii < 8; ii++) {
|
||||
sbyte = sbyte << 1;
|
||||
}
|
||||
luaL_addlstring(&b, (char *) &sbyte, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_NULL:
|
||||
{
|
||||
char nullbyte = 0;
|
||||
luaL_addlstring(&b, &nullbyte, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_HEX:
|
||||
{ // doing digit parsing the lpack way
|
||||
unsigned char sbyte = 0;
|
||||
size_t l;
|
||||
unsigned int ii = 0;
|
||||
int odd = 0;
|
||||
const char *a = luaL_checklstring(L, i++, &l);
|
||||
for (ii = 0; ii < l; ii++) {
|
||||
if (isxdigit((int) (unsigned char) a[ii])) {
|
||||
if (isdigit((int) (unsigned char) a[ii])) {
|
||||
sbyte += a[ii] - '0';
|
||||
odd++;
|
||||
} else if (a[ii] >= 'A' && a[ii] <= 'F') {
|
||||
sbyte += a[ii] - 'A' + 10;
|
||||
odd++;
|
||||
} else if (a[ii] >= 'a' && a[ii] <= 'f') {
|
||||
sbyte += a[ii] - 'a' + 10;
|
||||
odd++;
|
||||
}
|
||||
if (odd == 1) {
|
||||
sbyte = sbyte << 4;
|
||||
} else if (odd == 2) {
|
||||
luaL_addlstring(&b, (char *) &sbyte, 1);
|
||||
sbyte = 0;
|
||||
odd = 0;
|
||||
}
|
||||
} else if (isspace(a[ii])) {
|
||||
/* ignore */
|
||||
} else {
|
||||
/* err ... ignore too*/
|
||||
}
|
||||
}
|
||||
if (odd == 1) {
|
||||
luaL_addlstring(&b, (char *) &sbyte, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ' ': case ',':
|
||||
break;
|
||||
default:
|
||||
badcode(L,c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
luaL_pushresult(&b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg R[] =
|
||||
{
|
||||
{"pack", l_pack},
|
||||
{"unpack", l_unpack},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
int luaopen_lua_pack(lua_State *L)
|
||||
{
|
||||
lua_newtable(L);
|
||||
|
||||
lua_pushcfunction(L, &l_pack);
|
||||
lua_setfield(L, -2, "pack");
|
||||
|
||||
lua_pushcfunction(L, &l_unpack);
|
||||
lua_setfield(L, -2, "unpack");
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
local pack = require"lua_pack"
|
||||
|
||||
local bpack = pack.pack
|
||||
local bunpack = pack.unpack
|
||||
|
||||
function hex(s)
|
||||
s=string.gsub(s,"(.)",function (x) return string.format("%02X",string.byte(x)) end)
|
||||
return s
|
||||
end
|
||||
|
||||
a=bpack("AC8","\027Lua",5*16+1,0,1,4,4,4,8,0)
|
||||
print(hex(a),string.len(a))
|
||||
|
||||
b=string.dump(hex)
|
||||
b=string.sub(b,1,string.len(a))
|
||||
print(a==b,string.len(b))
|
||||
print(bunpack(b,"CA3C8"))
|
||||
|
||||
i=314159265 f="<I>I=I"
|
||||
a=bpack(f,i,i,i)
|
||||
print(hex(a))
|
||||
print(bunpack(a,f))
|
||||
|
||||
i=3.14159265 f="<d>d=d"
|
||||
a=bpack(f,i,i,i)
|
||||
print(hex(a))
|
||||
print(bunpack(a,f))
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
sudo: required
|
||||
dist: bionic
|
||||
dist: focal
|
||||
|
||||
branches:
|
||||
only:
|
||||
|
@ -16,7 +16,6 @@ compiler:
|
|||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- cpanminus
|
||||
- axel
|
||||
- luarocks
|
||||
- daemonize
|
||||
|
@ -56,7 +55,7 @@ before_install:
|
|||
- luacheck --globals coroutine -q .
|
||||
- '! grep -n -P ''(?<=.{80}).+'' --color `find . -name ''*.lua''` || (echo "ERROR: Found Lua source lines exceeding 80 columns." > /dev/stderr; exit 1)'
|
||||
- '! grep -n -P ''\t+'' --color `find . -name ''*.lua''` || (echo "ERROR: Cannot use tabs." > /dev/stderr; exit 1)'
|
||||
- sudo cpanm --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- cpanm --sudo --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1)
|
||||
|
||||
install:
|
||||
- if [ ! -d download-cache ]; then mkdir download-cache; fi
|
||||
|
|
|
@ -19,22 +19,22 @@ local FREE_LIST_REF = 0
|
|||
if subsystem == 'http' then
|
||||
if not ngx.config
|
||||
or not ngx.config.ngx_lua_version
|
||||
or ngx.config.ngx_lua_version ~= 10023
|
||||
or ngx.config.ngx_lua_version ~= 10024
|
||||
then
|
||||
error("ngx_http_lua_module 0.10.23 required")
|
||||
error("ngx_http_lua_module 0.10.24 required")
|
||||
end
|
||||
|
||||
elseif subsystem == 'stream' then
|
||||
if not ngx.config
|
||||
or not ngx.config.ngx_lua_version
|
||||
or ngx.config.ngx_lua_version ~= 12
|
||||
or ngx.config.ngx_lua_version ~= 13
|
||||
then
|
||||
error("ngx_stream_lua_module 0.0.12 required")
|
||||
error("ngx_stream_lua_module 0.0.13 required")
|
||||
end
|
||||
|
||||
else
|
||||
error("ngx_http_lua_module 0.10.23 or "
|
||||
.. "ngx_stream_lua_module 0.0.12 required")
|
||||
error("ngx_http_lua_module 0.10.24 or "
|
||||
.. "ngx_stream_lua_module 0.0.13 required")
|
||||
end
|
||||
|
||||
|
||||
|
@ -141,7 +141,7 @@ local c_buf_type = ffi.typeof("char[?]")
|
|||
local _M = new_tab(0, 18)
|
||||
|
||||
|
||||
_M.version = "0.1.25"
|
||||
_M.version = "0.1.26"
|
||||
_M.new_tab = new_tab
|
||||
_M.clear_tab = clear_tab
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ local get_string_buf = base.get_string_buf
|
|||
local get_size_ptr = base.get_size_ptr
|
||||
local setmetatable = setmetatable
|
||||
local lower = string.lower
|
||||
local find = string.find
|
||||
local rawget = rawget
|
||||
local ngx = ngx
|
||||
local get_request = base.get_request
|
||||
|
@ -114,7 +115,12 @@ local truncated = ffi.new("int[1]")
|
|||
|
||||
local req_headers_mt = {
|
||||
__index = function (tb, key)
|
||||
return rawget(tb, (str_replace_char(lower(key), '_', '-')))
|
||||
key = lower(key)
|
||||
local value = rawget(tb, key)
|
||||
if value == nil and find(key, '_', 1, true) then
|
||||
value = rawget(tb, (str_replace_char(key, '_', '-')))
|
||||
end
|
||||
return value
|
||||
end
|
||||
}
|
||||
|
||||
|
|
|
@ -2,13 +2,16 @@
|
|||
|
||||
|
||||
local ffi = require "ffi"
|
||||
local jit = require "jit"
|
||||
local base = require "resty.core.base"
|
||||
local ffi_cast = ffi.cast
|
||||
|
||||
|
||||
local C = ffi.C
|
||||
local ffi_new = ffi.new
|
||||
local new_tab = base.new_tab
|
||||
local subsystem = ngx.config.subsystem
|
||||
local get_string_buf = base.get_string_buf
|
||||
local get_size_ptr = base.get_size_ptr
|
||||
|
||||
|
||||
local ngx_lua_ffi_worker_id
|
||||
|
@ -16,6 +19,8 @@ local ngx_lua_ffi_worker_pid
|
|||
local ngx_lua_ffi_worker_pids
|
||||
local ngx_lua_ffi_worker_count
|
||||
local ngx_lua_ffi_worker_exiting
|
||||
local ffi_intp_type = ffi.typeof("int *")
|
||||
local ffi_int_size = ffi.sizeof("int")
|
||||
|
||||
|
||||
ngx.worker = new_tab(0, 4)
|
||||
|
@ -25,31 +30,42 @@ if subsystem == "http" then
|
|||
ffi.cdef[[
|
||||
int ngx_http_lua_ffi_worker_id(void);
|
||||
int ngx_http_lua_ffi_worker_pid(void);
|
||||
int ngx_http_lua_ffi_worker_pids(int *pids, size_t *pids_len);
|
||||
int ngx_http_lua_ffi_worker_count(void);
|
||||
int ngx_http_lua_ffi_worker_exiting(void);
|
||||
]]
|
||||
|
||||
ngx_lua_ffi_worker_id = C.ngx_http_lua_ffi_worker_id
|
||||
ngx_lua_ffi_worker_pid = C.ngx_http_lua_ffi_worker_pid
|
||||
ngx_lua_ffi_worker_pids = C.ngx_http_lua_ffi_worker_pids
|
||||
ngx_lua_ffi_worker_count = C.ngx_http_lua_ffi_worker_count
|
||||
ngx_lua_ffi_worker_exiting = C.ngx_http_lua_ffi_worker_exiting
|
||||
if jit.os ~= "Windows" then
|
||||
ffi.cdef[[
|
||||
int ngx_http_lua_ffi_worker_pids(int *pids, size_t *pids_len);
|
||||
]]
|
||||
|
||||
ngx_lua_ffi_worker_pids = C.ngx_http_lua_ffi_worker_pids
|
||||
end
|
||||
|
||||
elseif subsystem == "stream" then
|
||||
ffi.cdef[[
|
||||
int ngx_stream_lua_ffi_worker_id(void);
|
||||
int ngx_stream_lua_ffi_worker_pid(void);
|
||||
int ngx_stream_lua_ffi_worker_pids(int *pids, size_t *pids_len);
|
||||
int ngx_stream_lua_ffi_worker_count(void);
|
||||
int ngx_stream_lua_ffi_worker_exiting(void);
|
||||
]]
|
||||
|
||||
ngx_lua_ffi_worker_id = C.ngx_stream_lua_ffi_worker_id
|
||||
ngx_lua_ffi_worker_pid = C.ngx_stream_lua_ffi_worker_pid
|
||||
ngx_lua_ffi_worker_pids = C.ngx_stream_lua_ffi_worker_pids
|
||||
ngx_lua_ffi_worker_count = C.ngx_stream_lua_ffi_worker_count
|
||||
ngx_lua_ffi_worker_exiting = C.ngx_stream_lua_ffi_worker_exiting
|
||||
|
||||
if jit.os ~= "Windows" then
|
||||
ffi.cdef[[
|
||||
int ngx_stream_lua_ffi_worker_pids(int *pids, size_t *pids_len);
|
||||
]]
|
||||
|
||||
ngx_lua_ffi_worker_pids = C.ngx_stream_lua_ffi_worker_pids
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
@ -62,23 +78,33 @@ function ngx.worker.pid()
|
|||
return ngx_lua_ffi_worker_pid()
|
||||
end
|
||||
|
||||
local size_ptr = ffi_new("size_t[1]")
|
||||
local pids_ptr = ffi_new("int[1024]") -- using NGX_MAX_PROCESSES
|
||||
|
||||
function ngx.worker.pids()
|
||||
if ngx.get_phase() == "init" or ngx.get_phase() == "init_worker" then
|
||||
return nil, "API disabled in the current context"
|
||||
end
|
||||
|
||||
local res = ngx_lua_ffi_worker_pids(pids_ptr, size_ptr)
|
||||
|
||||
local pids = {}
|
||||
if res == 0 then
|
||||
for i = 1, tonumber(size_ptr[0]) do
|
||||
pids[i] = pids_ptr[i-1]
|
||||
if jit.os ~= "Windows" then
|
||||
function ngx.worker.pids()
|
||||
if ngx.get_phase() == "init" or ngx.get_phase() == "init_worker" then
|
||||
return nil, "API disabled in the current context"
|
||||
end
|
||||
|
||||
local pids = {}
|
||||
local size_ptr = get_size_ptr()
|
||||
-- the old and the new workers coexist during reloading
|
||||
local worker_cnt = ngx.worker.count() * 4
|
||||
if worker_cnt == 0 then
|
||||
return pids
|
||||
end
|
||||
|
||||
size_ptr[0] = worker_cnt
|
||||
local pids_ptr = get_string_buf(worker_cnt * ffi_int_size)
|
||||
local intp_buf = ffi_cast(ffi_intp_type, pids_ptr)
|
||||
local res = ngx_lua_ffi_worker_pids(intp_buf, size_ptr)
|
||||
|
||||
if res == 0 then
|
||||
for i = 1, tonumber(size_ptr[0]) do
|
||||
pids[i] = intp_buf[i-1]
|
||||
end
|
||||
end
|
||||
return pids
|
||||
end
|
||||
return pids
|
||||
end
|
||||
|
||||
function ngx.worker.id()
|
||||
|
|
|
@ -140,6 +140,11 @@ qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/
|
|||
|
||||
|
||||
=== TEST 4: ngx.req.get_headers (metatable)
|
||||
--- http_config eval
|
||||
"
|
||||
$::HttpConfig
|
||||
underscores_in_headers on;
|
||||
"
|
||||
--- config
|
||||
location = /t {
|
||||
set $foo hello;
|
||||
|
@ -159,6 +164,10 @@ qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/
|
|||
for _, k in ipairs(keys) do
|
||||
ngx.say(k, ": ", headers[k])
|
||||
end
|
||||
|
||||
ngx.say("X_Bar_Header: ", headers["X_Bar_Header"])
|
||||
ngx.say("x_Bar_Header: ", headers["x_Bar_Header"])
|
||||
ngx.say("x_bar_header: ", headers["x_bar_header"])
|
||||
}
|
||||
}
|
||||
--- request
|
||||
|
@ -169,9 +178,14 @@ baz: baz
|
|||
connection: close
|
||||
foo-bar: foo
|
||||
host: localhost
|
||||
x_bar_header: bar
|
||||
X_Bar_Header: bar
|
||||
x_Bar_Header: bar
|
||||
x_bar_header: bar
|
||||
--- more_headers
|
||||
Foo-Bar: foo
|
||||
Baz: baz
|
||||
X_Bar_Header: bar
|
||||
--- wait: 0.2
|
||||
--- error_log eval
|
||||
qr/\[TRACE\s+\d+ .*? -> \d+\]/
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
{{ if .Versions -}}
|
||||
<a name="unreleased"></a>
|
||||
## [Unreleased]
|
||||
|
||||
{{ if .Unreleased.CommitGroups -}}
|
||||
{{ range .Unreleased.CommitGroups -}}
|
||||
### {{ .Title }}
|
||||
{{ range .Commits -}}
|
||||
- {{ if .Scope }}**{{ replace .Scope "*" "\\*" -1 }}:** {{ end }}{{ .Subject }}
|
||||
{{ end }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
|
||||
{{ range .Versions }}
|
||||
<a name="{{ .Tag.Name }}"></a>
|
||||
## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }}
|
||||
{{ range .CommitGroups -}}
|
||||
### {{ lower .Title }}
|
||||
{{ range .Commits -}}
|
||||
- {{ if .Scope }}**{{ replace .Scope "*" "\\*" -1 }}:** {{ end }}{{ .Subject }} [{{ .Hash.Short }}]({{ $.Info.RepositoryURL }}/commit/{{ .Hash.Long }})
|
||||
{{ end }}
|
||||
{{ end -}}
|
||||
|
||||
{{- if .NoteGroups -}}
|
||||
{{ range .NoteGroups -}}
|
||||
### {{ .Title }}
|
||||
{{ range .Notes }}
|
||||
{{ .Body }}
|
||||
{{ end }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
|
||||
{{- if .Versions }}
|
||||
[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD
|
||||
{{ range .Versions -}}
|
||||
{{ if .Tag.Previous -}}
|
||||
[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
|
@ -0,0 +1,29 @@
|
|||
style: github
|
||||
template: CHANGELOG.tpl.md
|
||||
info:
|
||||
title: CHANGELOG
|
||||
repository_url: https://github.com/fffonion/lua-resty-openssl
|
||||
options:
|
||||
sort: "semver"
|
||||
commits:
|
||||
filters:
|
||||
Type:
|
||||
- feat
|
||||
- fix
|
||||
- perf
|
||||
- refactor
|
||||
commit_groups:
|
||||
title_maps:
|
||||
feat: Features
|
||||
fix: Bug Fixes
|
||||
perf: Performance Improvements
|
||||
refactor: Code Refactoring
|
||||
header:
|
||||
pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s\\/]*)\\))?\\s(.*)$"
|
||||
pattern_maps:
|
||||
- Type
|
||||
- Scope
|
||||
- Subject
|
||||
notes:
|
||||
keywords:
|
||||
- BREAKING CHANGE
|
|
@ -0,0 +1,14 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
charset = utf-8
|
||||
|
||||
[*.lua]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
|
@ -0,0 +1,32 @@
|
|||
name: Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- lib/**.lua
|
||||
pull_request:
|
||||
paths:
|
||||
- lib/**.lua
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
name: Lint
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v2
|
||||
- uses: Jayrgo/luacheck-action@v1
|
||||
name: luacheck
|
||||
with:
|
||||
# List of files, directories and rockspecs to check.
|
||||
# Default: .
|
||||
files: 'lib'
|
||||
|
||||
# Path to configuration file.
|
||||
# Default: .luacheckrc
|
||||
config: '.luacheckrc'
|
||||
|
||||
# Arguments passed to luacheck.
|
||||
# Default: -q
|
||||
args: '-q'
|
|
@ -0,0 +1,299 @@
|
|||
name: Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- release/*
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
name: Tests
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
# TODO: arm64
|
||||
# latest and one version older for valgrind
|
||||
- nginx: "1.19.9"
|
||||
openssl: "1.0.2u"
|
||||
valgrind: "valgrind"
|
||||
lua_nginx_module: "v0.10.20"
|
||||
lua_resty_core: "v0.1.22"
|
||||
- nginx: "1.19.9"
|
||||
openssl: "1.1.1s"
|
||||
valgrind: "valgrind"
|
||||
lua_nginx_module: "v0.10.20"
|
||||
lua_resty_core: "v0.1.22"
|
||||
- nginx: "1.19.9"
|
||||
openssl: "3.0.8"
|
||||
valgrind: "valgrind"
|
||||
openssl_opts: "enable-fips"
|
||||
lua_nginx_module: "v0.10.20"
|
||||
lua_resty_core: "v0.1.22"
|
||||
nginx_cc_opts: "-Wno-error"
|
||||
- nginx: "1.21.4"
|
||||
openssl: "1.0.2u"
|
||||
valgrind: "valgrind"
|
||||
lua_nginx_module: "v0.10.21"
|
||||
lua_resty_core: "v0.1.23"
|
||||
- nginx: "1.21.4"
|
||||
openssl: "1.1.1s"
|
||||
valgrind: "valgrind"
|
||||
lua_nginx_module: "v0.10.21"
|
||||
lua_resty_core: "v0.1.23"
|
||||
- nginx: "1.21.4"
|
||||
openssl: "3.0.8"
|
||||
valgrind: "valgrind"
|
||||
openssl_opts: "enable-fips"
|
||||
lua_nginx_module: "v0.10.21"
|
||||
lua_resty_core: "v0.1.23"
|
||||
nginx_cc_opts: "-Wno-error"
|
||||
- nginx: "1.21.4"
|
||||
openssl: "3.1.0-beta1"
|
||||
valgrind: "valgrind"
|
||||
openssl_opts: "enable-fips"
|
||||
lua_nginx_module: "v0.10.21"
|
||||
lua_resty_core: "v0.1.23"
|
||||
nginx_cc_opts: "-Wno-error"
|
||||
# latest version with EOL 1.1.0
|
||||
- nginx: "1.21.4"
|
||||
openssl: "1.1.0l"
|
||||
lua_nginx_module: "v0.10.21"
|
||||
lua_resty_core: "v0.1.23"
|
||||
# version that kong uses, for fips
|
||||
- nginx: "1.21.4"
|
||||
openssl: "1.0.2u"
|
||||
fips2: "2.0.16"
|
||||
openssl_opts: "fips --with-fipsdir=/home/runner/work/cache/ssl/fips"
|
||||
valgrind: "valgrind"
|
||||
lua_nginx_module: "v0.10.21"
|
||||
lua_resty_core: "v0.1.23"
|
||||
- nginx: "1.21.4"
|
||||
boringssl: "ae223d6138807a13006342edfeef32e813246b39" # fips-20190808
|
||||
valgrind: "valgrind"
|
||||
lua_nginx_module: "v0.10.21"
|
||||
lua_resty_core: "v0.1.23"
|
||||
- nginx: "1.21.4"
|
||||
boringssl: "853ca1ea1168dff08011e5d42d94609cc0ca2e27" # fips-20210429, not active yet
|
||||
valgrind: "valgrind"
|
||||
lua_nginx_module: "v0.10.21"
|
||||
lua_resty_core: "v0.1.23"
|
||||
|
||||
env:
|
||||
JOBS: 3
|
||||
SH: bash
|
||||
NGX_BUILD_JOBS: 3
|
||||
BASE_PATH: /home/runner/work/cache
|
||||
LUAJIT_PREFIX: /home/runner/work/cache/luajit21
|
||||
LUAJIT_LIB: /home/runner/work/cache/luajit21/lib
|
||||
LUAJIT_INC: /home/runner/work/cache/luajit21/include/luajit-2.1
|
||||
LUA_INCLUDE_DIR: /home/runner/work/cache/luajit21/include/luajit-2.1
|
||||
OPENSSL_PREFIX: /home/runner/work/cache/ssl
|
||||
# lib64 since openssl 3.0
|
||||
OPENSSL_LIB: /home/runner/work/cache/ssl/lib64
|
||||
OPENSSL_INC: /home/runner/work/cache/ssl/include
|
||||
TEST_NGINX_SLEEP: 0.005
|
||||
TEST_NGINX_RANDOMIZE: 1
|
||||
LUACHECK_VER: 0.21.1
|
||||
CC: gcc
|
||||
NGX_BUILD_CC: gcc
|
||||
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
/home/runner/work/cache
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/tests.yml') }}-nginx-${{ matrix.nginx }}-openssl-${{ matrix.openssl }}-${{ matrix.fips2 }}-boringssl-${{ matrix.boringssl }}
|
||||
|
||||
- name: Setup tools
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -qq -y cpanminus axel ca-certificates valgrind haveged
|
||||
mkdir -p $OPENSSL_PREFIX $LUAJIT_PREFIX
|
||||
# perl cache
|
||||
pushd /home/runner/work/cache
|
||||
if [ ! -e perl ]; then sudo cpanm --notest Test::Nginx > build.log 2>&1 || (cat build.log && exit 1); cp -r /usr/local/share/perl/ .; else sudo cp -r perl /usr/local/share; fi
|
||||
# build tools at parent directory of cache
|
||||
cd ..
|
||||
git clone https://github.com/openresty/openresty.git ./openresty
|
||||
git clone https://github.com/openresty/nginx-devel-utils.git
|
||||
git clone https://github.com/simpl/ngx_devel_kit.git ./ndk-nginx-module
|
||||
git clone https://github.com/openresty/lua-nginx-module.git ./lua-nginx-module -b ${{ matrix.lua_nginx_module }}
|
||||
git clone https://github.com/openresty/no-pool-nginx.git ./no-pool-nginx
|
||||
git clone https://github.com/fffonion/lua-resty-openssl-aux-module ./lua-resty-openssl-aux-module
|
||||
# lua libraries at parent directory of current repository
|
||||
popd
|
||||
git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core -b ${{ matrix.lua_resty_core }}
|
||||
git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache
|
||||
git clone https://github.com/jkeys089/lua-resty-hmac ../lua-resty-hmac && pushd ../lua-resty-hmac && git checkout 79a4929 && popd
|
||||
git clone https://github.com/openresty/lua-resty-string ../lua-resty-string
|
||||
|
||||
- name: Build OpenSSL
|
||||
if: matrix.boringssl == ''
|
||||
run: |
|
||||
mkdir -p $OPENSSL_PREFIX
|
||||
# fips doesn't seem to support to build parallelly
|
||||
if [ "X${{ matrix.fips2 }}" != "X" ]; then wget https://www.openssl.org/source/old/fips/openssl-fips-${{ matrix.fips2 }}.tar.gz -qO - | tar zxf - ; pushd openssl-fips-${{ matrix.fips2 }}/; FIPSDIR=$OPENSSL_PREFIX/fips ./config; make; make install; popd; fi
|
||||
if [ "X$OPENSSL_HASH" != "X" ]; then wget https://github.com/openssl/openssl/archive/$OPENSSL_HASH.tar.gz -qO - | tar zxf ; pushd openssl-$OPENSSL_HASH/; fi
|
||||
if [ "X$OPENSSL_HASH" = "X" ] ; then wget https://www.openssl.org/source/openssl-${{ matrix.openssl }}.tar.gz -qO - | tar zxf -; pushd openssl-${{ matrix.openssl }}/; fi
|
||||
if [ ! -e $OPENSSL_PREFIX/include ]; then ./config shared -d --prefix=$OPENSSL_PREFIX -DPURIFY ${{ matrix.openssl_opts }} > build.log 2>&1 || (cat build.log && exit 1); fi
|
||||
if [ ! -e $OPENSSL_PREFIX/include ]; then make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); fi
|
||||
if [ ! -e $OPENSSL_PREFIX/include ]; then sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1); fi
|
||||
if [ -e $OPENSSL_LIB/libcrypto.so.3 ] && [ ! -e $OPENSSL_LIB/ossl-modules/fips.so ]; then mkdir -p $OPENSSL_PREFIX/ssl; sudo make PATH=$PATH install_fips > build.log 2>&1 || (cat build.log && exit 1); fi
|
||||
if [ ! -e $OPENSSL_PREFIX/lib64 ]; then sudo cp -r $OPENSSL_PREFIX/lib $OPENSSL_PREFIX/lib64; fi
|
||||
mkdir -p $OPENSSL_PREFIX/certs/ && sudo cp -r /etc/ssl/certs/* $OPENSSL_PREFIX/certs/
|
||||
|
||||
- name: Build BoringSSL
|
||||
if: matrix.boringssl != ''
|
||||
run: |
|
||||
mkdir -p $OPENSSL_PREFIX
|
||||
if [ ! -e $OPENSSL_PREFIX/include ]; then
|
||||
# libtinfo5 is a dependency of clang7 on ubuntu20.04
|
||||
sudo apt-get install -qq -y cmake libtinfo5 unzip libunwind-dev libgcc-9-dev libstdc++-9-dev
|
||||
|
||||
wget https://releases.llvm.org/7.0.1/clang+llvm-7.0.1-x86_64-linux-gnu-ubuntu-18.04.tar.xz -qO - |tar Jxf -
|
||||
export HOME="$PWD"
|
||||
printf "set(CMAKE_C_COMPILER \"clang\")\nset(CMAKE_CXX_COMPILER \"clang++\")\n" > ${HOME}/toolchain
|
||||
export PATH="$PWD/clang+llvm-7.0.1-x86_64-linux-gnu-ubuntu-18.04/bin:$PATH"
|
||||
clang --version
|
||||
|
||||
wget https://dl.google.com/go/go1.12.7.linux-amd64.tar.gz -qO - |tar zxf -
|
||||
export GOPATH="$PWD/gopath"
|
||||
export GOROOT="$PWD/go"
|
||||
export PATH="$GOPATH/bin:$GOROOT/bin:$PATH"
|
||||
go version
|
||||
|
||||
wget https://github.com/ninja-build/ninja/releases/download/v1.9.0/ninja-linux.zip -q
|
||||
unzip -o ninja-linux.zip
|
||||
export PATH="$PWD:$PATH"
|
||||
ninja --version
|
||||
|
||||
wget https://commondatastorage.googleapis.com/chromium-boringssl-fips/boringssl-${{ matrix.boringssl }}.tar.xz -qO - | tar Jxf -; pushd boringssl
|
||||
if [ "${{ matrix.boringssl }}" == "ae223d6138807a13006342edfeef32e813246b39" ]; then
|
||||
patch -p1 < ../t/fixtures/boringssl_fips.patch
|
||||
fi
|
||||
rm -rf build; mkdir build; pushd build
|
||||
cmake -GNinja -DCMAKE_TOOLCHAIN_FILE=${HOME}/toolchain -DFIPS=1 -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=1 .. > build.log 2>&1 || (cat build.log && exit 1)
|
||||
ninja > build.log 2>&1 || (cat build.log && exit 1)
|
||||
|
||||
./tool/bssl isfips
|
||||
|
||||
popd; rm -rf $OPENSSL_INC; cp -r include $OPENSSL_INC
|
||||
mkdir -p $OPENSSL_LIB; cp -r build/*/*.so $OPENSSL_LIB
|
||||
fi
|
||||
mkdir -p $OPENSSL_PREFIX/certs/ && sudo cp -r /etc/ssl/certs/* $OPENSSL_PREFIX/certs/
|
||||
|
||||
- name: Build LuaJIT
|
||||
env:
|
||||
LUAJIT_CC_OPTS: ${{ matrix.luajit_cc_opts }}
|
||||
run: |
|
||||
if [ "X${{ matrix.valgrind }}" != "X" ]; then LUAJIT_CC_OPTS="$LUAJIT_CC_OPTS -DLUAJIT_NUMMODE=2 -DLUAJIT_${{ matrix.valgrind }} -DLUAJIT_USE_SYSMALLOC -O0"; fi
|
||||
export
|
||||
cd $LUAJIT_PREFIX
|
||||
if [ ! -e luajit2 ]; then git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git; fi
|
||||
cd luajit2
|
||||
make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS="-DLUA_USE_APICHECK -DLUA_USE_ASSERT -DLUAJIT_ENABLE_LUA52COMPAT ${{ matrix.luajit_cc_opts }}" > build.log 2>&1 || (cat build.log && exit 1)
|
||||
make install PREFIX=$LUAJIT_PREFIX > build.log 2>&1 || (cat build.log && exit 1)
|
||||
|
||||
- name: Build lua-cjson
|
||||
run: |
|
||||
if [ ! -e lua-cjson ]; then git clone https://github.com/openresty/lua-cjson.git ./lua-cjson; fi
|
||||
pushd ./lua-cjson && make && sudo PATH=$PATH make install && popd
|
||||
|
||||
- name: Build Nginx
|
||||
env:
|
||||
NGINX_CC_OPTS: ${{ matrix.nginx_cc_opts }}
|
||||
run: |
|
||||
if [ "X${{ matrix.valgrind }}" != "X" ]; then NGINX_CC_OPTS="$NGINX_CC_OPTS -O0"; fi
|
||||
export PATH=$BASE_PATH/work/nginx/sbin:$BASE_PATH/../nginx-devel-utils:$PATH
|
||||
export LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH
|
||||
export NGX_LUA_LOC=$BASE_PATH/../lua-nginx-module
|
||||
export NGX_STREAM_LUA_LOC=$BASE_PATH/../stream-lua-nginx-module
|
||||
export
|
||||
cd $BASE_PATH
|
||||
if [ ! -e work ]; then ngx-build ${{ matrix.nginx }} --add-module=../ndk-nginx-module --add-module=../lua-nginx-module --add-module=../lua-resty-openssl-aux-module --with-http_ssl_module --with-cc-opt="-I$OPENSSL_INC $NGINX_CC_OPTS" --with-ld-opt="-L$OPENSSL_LIB -Wl,-rpath,$OPENSSL_LIB" --with-debug > build.log 2>&1 || (cat build.log && exit 1); fi
|
||||
nginx -V
|
||||
ldd `which nginx`|grep -E 'luajit|ssl|pcre'
|
||||
|
||||
- name: Run Test
|
||||
run: |
|
||||
export LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH
|
||||
export PATH=$BASE_PATH/work/nginx/sbin:$PATH
|
||||
TEST_NGINX_TIMEOUT=20 prove -j$JOBS -r t/ 2>&1
|
||||
|
||||
echo "Nginx SSL plain FFI"
|
||||
export CI_SKIP_NGINX_C=1
|
||||
TEST_NGINX_TIMEOUT=10 prove -j$JOBS t/openssl/ssl/ 2>&1
|
||||
|
||||
- name: Run Valgrind
|
||||
if: matrix.valgrind != ''
|
||||
run: |
|
||||
export LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH
|
||||
export TEST_NGINX_VALGRIND='--num-callers=100 -q --tool=memcheck --leak-check=full --show-possibly-lost=no --gen-suppressions=all --suppressions=valgrind.suppress --track-origins=yes' TEST_NGINX_TIMEOUT=60 TEST_NGINX_SLEEP=1
|
||||
export PATH=$BASE_PATH/work/nginx/sbin:$PATH
|
||||
stdbuf -o 0 -e 0 prove -j$JOBS -r t/ 2>&1 | grep -v "Connection refused" | grep -v "Retry connecting after" | tee output.log
|
||||
if grep -q 'insert_a_suppression_name_here' output.log; then echo "Valgrind found problems"; exit 1; fi
|
||||
|
||||
echo "Nginx SSL plain FFI"
|
||||
export CI_SKIP_NGINX_C=1
|
||||
stdbuf -o 0 -e 0 prove -j$JOBS t/openssl/ssl/ 2>&1 | grep -v "Connection refused" | grep -v "Retry connecting after" | tee output.log
|
||||
if grep -q 'insert_a_suppression_name_here' output.log; then echo "Valgrind found problems"; exit 1; fi
|
||||
|
||||
- name: Run FIPS Test
|
||||
run: |
|
||||
# openssl 3.0
|
||||
if [ -e $OPENSSL_LIB/libcrypto.so.3 ]; then
|
||||
echo "FIPS for OpenSSL 3.0"
|
||||
cp t/fixtures/openssl_fips.cnf $OPENSSL_PREFIX/openssl-fips.cnf
|
||||
|
||||
pushd openssl-${{ matrix.openssl }}/;
|
||||
# LD_LIBRARY_PATH=$OPENSSL_LIB $OPENSSL_PREFIX/bin/openssl fipsinstall -out $OPENSSL_PREFIX/fipsmodule.cnf -module $OPENSSL_LIB/ossl-modules/fips.so
|
||||
# don't activate by default
|
||||
sed -i "/activate = 1/d" $OPENSSL_PREFIX/ssl/fipsmodule.cnf
|
||||
cat $OPENSSL_PREFIX/ssl/fipsmodule.cnf >> $OPENSSL_PREFIX/openssl-fips.cnf
|
||||
export OPENSSL_CONF=$OPENSSL_PREFIX/openssl-fips.cnf
|
||||
popd
|
||||
|
||||
export TEST_NGINX_FIPS=1
|
||||
fi
|
||||
|
||||
# openssl 1.0.2 with fips module
|
||||
if [ "X${{ matrix.fips2 }}" != "X" ]; then
|
||||
echo "FIPS for OpenSSL 1.0.2"
|
||||
export TEST_NGINX_FIPS=1
|
||||
fi
|
||||
|
||||
# BoringSSL
|
||||
if [ "X${{ matrix.boringssl }}" != "X" ]; then
|
||||
echo "FIPS for BoringSSL ${{ matrix.boringssl }}"
|
||||
export TEST_NGINX_FIPS=1
|
||||
fi
|
||||
|
||||
if [ "X$TEST_NGINX_FIPS" != "X" ]; then
|
||||
echo "Running FIPS tests"
|
||||
|
||||
export LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH
|
||||
export PATH=$BASE_PATH/work/nginx/sbin:$PATH
|
||||
|
||||
TEST_NGINX_FIPS=1 TEST_NGINX_TIMEOUT=10 prove -j$JOBS -r t/ 2>&1
|
||||
|
||||
TEST_NGINX_TIMEOUT=20 prove -j$JOBS -r t/ 2>&1
|
||||
fi
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
t/servroot
|
||||
__pycache__
|
||||
.idea/
|
|
@ -0,0 +1,15 @@
|
|||
std = "ngx_lua"
|
||||
unused_args = false
|
||||
redefined = false
|
||||
max_line_length = false
|
||||
|
||||
|
||||
not_globals = {
|
||||
"string.len",
|
||||
"table.getn",
|
||||
}
|
||||
|
||||
|
||||
ignore = {
|
||||
"6.", -- ignore whitespace warnings
|
||||
}
|
|
@ -0,0 +1,546 @@
|
|||
<a name="unreleased"></a>
|
||||
## [Unreleased]
|
||||
|
||||
|
||||
<a name="0.8.21"></a>
|
||||
## [0.8.21] - 2023-03-24
|
||||
### features
|
||||
- **x509.store:** extend verify to support setting flags ([#104](https://github.com/fffonion/lua-resty-openssl/issues/104)) [fa45b6c](https://github.com/fffonion/lua-resty-openssl/commit/fa45b6ce197dee7e2a55601bd4833f415c6cbaa2)
|
||||
|
||||
|
||||
<a name="0.8.20"></a>
|
||||
## [0.8.20] - 2023-03-10
|
||||
### bug fixes
|
||||
- **pkey:** use group bits instead of ECDSA_sig to get parameter size in ECDSA signature ([#102](https://github.com/fffonion/lua-resty-openssl/issues/102)) [f12cbfc](https://github.com/fffonion/lua-resty-openssl/commit/f12cbfc123490c666e2cbd7bec90948910a02336)
|
||||
|
||||
|
||||
<a name="0.8.19"></a>
|
||||
## [0.8.19] - 2023-03-10
|
||||
### bug fixes
|
||||
- **pkey:** fix signature length for secp521r1 ecdsa signature length ([#100](https://github.com/fffonion/lua-resty-openssl/issues/100)) [b7303d4](https://github.com/fffonion/lua-resty-openssl/commit/b7303d49cf738fe134f3e5efbf6157c96ff85237)
|
||||
|
||||
|
||||
<a name="0.8.18"></a>
|
||||
## [0.8.18] - 2023-03-04
|
||||
### features
|
||||
- **bn:** to_binary supports left padding of zeros [d59cac9](https://github.com/fffonion/lua-resty-openssl/commit/d59cac9d7e019e1bcdeaa6714f61294c354cf141)
|
||||
- **pkey:** allow to convert to and from binary format of ecdsa signature [9a20323](https://github.com/fffonion/lua-resty-openssl/commit/9a203233a23dd08d8f7eeaaff0599921d752a2e2)
|
||||
|
||||
|
||||
<a name="0.8.17"></a>
|
||||
## [0.8.17] - 2023-01-20
|
||||
### bug fixes
|
||||
- **\*:** support OpenSSL 3.1 [dc932f3](https://github.com/fffonion/lua-resty-openssl/commit/dc932f394e5c2b94129b406480897535ec561355)
|
||||
- **pkey:** allow one shot sign/verify in BoringSSL [32e5df3](https://github.com/fffonion/lua-resty-openssl/commit/32e5df37ac1aaa060c2c1f9b599bd194247d5ecb)
|
||||
|
||||
|
||||
<a name="0.8.16"></a>
|
||||
## [0.8.16] - 2022-12-20
|
||||
### features
|
||||
- **pkey:** load PKCS[#1](https://github.com/fffonion/lua-resty-openssl/issues/1) PEM encoded RSAPublicKey and RSAPrivateKey [3246ec0](https://github.com/fffonion/lua-resty-openssl/commit/3246ec0e51252bfa2812d49f9c6385dcaf0af10b)
|
||||
|
||||
|
||||
<a name="0.8.15"></a>
|
||||
## [0.8.15] - 2022-10-28
|
||||
### bug fixes
|
||||
- **pkey:** check private key existence before doing sign ([#83](https://github.com/fffonion/lua-resty-openssl/issues/83)) [eefcd2a](https://github.com/fffonion/lua-resty-openssl/commit/eefcd2a80b240f44be0bdadd1c2ccc28612004c0)
|
||||
|
||||
|
||||
<a name="0.8.14"></a>
|
||||
## [0.8.14] - 2022-10-21
|
||||
### bug fixes
|
||||
- **x509.crl:** fix metamethods when revoked is empty ([#79](https://github.com/fffonion/lua-resty-openssl/issues/79)) [e65adc7](https://github.com/fffonion/lua-resty-openssl/commit/e65adc7f132628c97e4db69cb5c4b13ff9cf0abf)
|
||||
|
||||
|
||||
<a name="0.8.13"></a>
|
||||
## [0.8.13] - 2022-10-14
|
||||
### bug fixes
|
||||
- **x509.\*:** fix set_extension will fail when a extension with same NID is not exist yet ([#75](https://github.com/fffonion/lua-resty-openssl/issues/75)) [b2f57b8](https://github.com/fffonion/lua-resty-openssl/commit/b2f57b860509a371ab1df71bbbc9e176e5a4d004)
|
||||
|
||||
### features
|
||||
- **x509.altname:** support set and get IP addresses ([#74](https://github.com/fffonion/lua-resty-openssl/issues/74)) [363c80d](https://github.com/fffonion/lua-resty-openssl/commit/363c80d1f2c7ba29dce268e213a9a16c9eae2953)
|
||||
- **x509.store:** add set_flags ([#77](https://github.com/fffonion/lua-resty-openssl/issues/77)) [8f3f16a](https://github.com/fffonion/lua-resty-openssl/commit/8f3f16a2b6d6c0f680c781f20a9e84a631da9aa5)
|
||||
|
||||
|
||||
<a name="0.8.11"></a>
|
||||
## [0.8.11] - 2022-10-12
|
||||
### performance improvements
|
||||
- **\*:** reuse cdata to improve performance [fc9cecd](https://github.com/fffonion/lua-resty-openssl/commit/fc9cecd785fc0193290cc3398d1ebbe7ae66fe15)
|
||||
|
||||
|
||||
<a name="0.8.10"></a>
|
||||
## [0.8.10] - 2022-06-24
|
||||
### features
|
||||
- **x509:** add get_signature_digest_name [d54b5d6](https://github.com/fffonion/lua-resty-openssl/commit/d54b5d61bc14813121f4a6bda2e1d7eab215094a)
|
||||
|
||||
|
||||
<a name="0.8.9"></a>
|
||||
## [0.8.9] - 2022-06-23
|
||||
### bug fixes
|
||||
- **aux/nginx:** add nginx 1.21.4 and ngx_lua 0.10.21 to support matrix [028da56](https://github.com/fffonion/lua-resty-openssl/commit/028da56d7de606d4b4b323fb3686ad4d93f69c7d)
|
||||
|
||||
|
||||
<a name="0.8.8"></a>
|
||||
## [0.8.8] - 2022-04-14
|
||||
### bug fixes
|
||||
- **ctx:** use global ctx where request is unavailable [e3590cf](https://github.com/fffonion/lua-resty-openssl/commit/e3590cfcbeb6f0d5f110c3c4e1b6cdc63b88e001)
|
||||
- **x509.extension:** correct X509V3_CTX size for OpenSSL 3.0 [0946c59](https://github.com/fffonion/lua-resty-openssl/commit/0946c5937fa9fa4bb41a70267a67fcc87307b6a6)
|
||||
|
||||
### features
|
||||
- **x509.extension:** add X509V3_set_issuer_pkey in OpenSSL 3.0 [dbd3f74](https://github.com/fffonion/lua-resty-openssl/commit/dbd3f7418a665ae797e6ffc71ba1d7f0660c95f0)
|
||||
- **x509.store:** add set_purpose and verify_method parameter [b7500fe](https://github.com/fffonion/lua-resty-openssl/commit/b7500fe7212c26070363afeab4a8acfe44c3cfc8)
|
||||
|
||||
|
||||
<a name="0.8.7"></a>
|
||||
## [0.8.7] - 2022-03-18
|
||||
### features
|
||||
- **x509.crl:** add functions to find and inspect revoked list in CRL [37c1661](https://github.com/fffonion/lua-resty-openssl/commit/37c1661fbebebad3b804f602f631e4ba65b80e07)
|
||||
|
||||
|
||||
<a name="0.8.6"></a>
|
||||
## [0.8.6] - 2022-03-16
|
||||
### bug fixes
|
||||
- **obj:** clean up stale error occured from OBJ_txt2* [219a2f0](https://github.com/fffonion/lua-resty-openssl/commit/219a2f0cace8480800394d6e88b188138f2650a1)
|
||||
- **pkey:** clear_error in passphrase type mismatch [8577422](https://github.com/fffonion/lua-resty-openssl/commit/857742273629d4e801a2d862644213fe5fdbf02a)
|
||||
- **x509.\*:** move clear_error to last when loading [369eea1](https://github.com/fffonion/lua-resty-openssl/commit/369eea1e4a1a185055296e07f272a3e470442916)
|
||||
|
||||
### features
|
||||
- **openssl:** add function to list SSL ciphers [9861af1](https://github.com/fffonion/lua-resty-openssl/commit/9861af1a074f74f529e341049ada29cbf7d57a48)
|
||||
- **ssl:** refine various handshake controlling functions [30bf41e](https://github.com/fffonion/lua-resty-openssl/commit/30bf41e958775f60afff1976fe731978c816dd25)
|
||||
|
||||
|
||||
<a name="0.8.5"></a>
|
||||
## [0.8.5] - 2022-02-02
|
||||
### bug fixes
|
||||
- **\*:** correct size type in cipher, hmac and rand in BoringSSL [54ce5f0](https://github.com/fffonion/lua-resty-openssl/commit/54ce5f0dd1861f2af15eacea154c805a237c03d8)
|
||||
- **bn:** use BN_check_prime in OpenSSL 3.0 [8c107e3](https://github.com/fffonion/lua-resty-openssl/commit/8c107e3dcf2006d6c453234278ab0a45109042d6)
|
||||
- **kdf:** correct FFI definition for BoringSSL [30ba7cf](https://github.com/fffonion/lua-resty-openssl/commit/30ba7cf9d90d8bc611cbccdca83e69c308739b60)
|
||||
- **stack:** correct indices to use size_t in BoringSSL [526ecb8](https://github.com/fffonion/lua-resty-openssl/commit/526ecb89c81b0e477b749a2424231329e468ce02)
|
||||
|
||||
### features
|
||||
- **\*:** add more modules for OSSL_LIB_CTX support [35f4bcb](https://github.com/fffonion/lua-resty-openssl/commit/35f4bcb796bc2fbe4ab066b8f78047bf30118986)
|
||||
|
||||
|
||||
<a name="0.8.4"></a>
|
||||
## [0.8.4] - 2021-12-20
|
||||
### bug fixes
|
||||
- **x509.\*:** use SHA256 as default sign digest in BoringSSL [355681a](https://github.com/fffonion/lua-resty-openssl/commit/355681a33d88d85de0faae3e8eb6685e0e3b9f34)
|
||||
|
||||
### features
|
||||
- **pkey:** add pkey:get_default_digest_type [0572e57](https://github.com/fffonion/lua-resty-openssl/commit/0572e57e0ab418f2dd749dbc5042b0c680e346a7)
|
||||
|
||||
|
||||
<a name="0.8.3"></a>
|
||||
## [0.8.3] - 2021-12-16
|
||||
### bug fixes
|
||||
- **hmac:** include evp.md headers [125ea05](https://github.com/fffonion/lua-resty-openssl/commit/125ea059da6b1effef7a187c434ebd6022dc3b82)
|
||||
|
||||
|
||||
<a name="0.8.2"></a>
|
||||
## [0.8.2] - 2021-11-22
|
||||
### bug fixes
|
||||
- **jwk:** fix typo of secp521r1 [81d2a64](https://github.com/fffonion/lua-resty-openssl/commit/81d2a646bde7a66ab87e127eace0d40aa714be58)
|
||||
|
||||
|
||||
<a name="0.8.1"></a>
|
||||
## [0.8.1] - 2021-11-05
|
||||
### bug fixes
|
||||
- **ssl_ctx:** fix typo when getting SSL_CTX from request [7b9e90f](https://github.com/fffonion/lua-resty-openssl/commit/7b9e90faef8337c759c281172be8c1f599be704d)
|
||||
|
||||
### features
|
||||
- **ctx:** add ctx module to provide OSSL_LIB_CTX context [65750bf](https://github.com/fffonion/lua-resty-openssl/commit/65750bfd800b2eebeb9bf653a03518f3ad235fba)
|
||||
|
||||
|
||||
<a name="0.8.0"></a>
|
||||
## [0.8.0] - 2021-10-29
|
||||
### bug fixes
|
||||
- **\*:** move EVP_* definition into seperate files [e0c3d61](https://github.com/fffonion/lua-resty-openssl/commit/e0c3d6178e8b0baab5c53d331dedf8ffb1b1b0c7)
|
||||
- **auxiliary/nginx:** set off_t to 64bit per nginx config ([#32](https://github.com/fffonion/lua-resty-openssl/issues/32)) [8c209fa](https://github.com/fffonion/lua-resty-openssl/commit/8c209fabbd4ba2f1d6f3a267059c758b4697a433)
|
||||
- **pkey:** allow sign/verify without md_alg for EdDSA on BoringSSL [ab83fd4](https://github.com/fffonion/lua-resty-openssl/commit/ab83fd4fc053f496699d5dcc77dbb551e2389e77)
|
||||
- **x509:** compatibility for BoringSSL 1.1.0 (fips-20190808) [84244af](https://github.com/fffonion/lua-resty-openssl/commit/84244af7d91e3421dfccdf1940beb70adbd66adb)
|
||||
|
||||
### features
|
||||
- **evp:** add geneirc function to get and set params [c724e1d](https://github.com/fffonion/lua-resty-openssl/commit/c724e1d41010fab7fb112ca3674eef1aab0b06be)
|
||||
- **kdf:** add new API with EVP_KDF interfaces [2336ae3](https://github.com/fffonion/lua-resty-openssl/commit/2336ae3b9a7a05473e251a10523a7357afb6f2f2)
|
||||
- **mac:** add EVP_MAC [0625be9](https://github.com/fffonion/lua-resty-openssl/commit/0625be92e0eaf6a9ee61b3499690d6079aaf933d)
|
||||
- **openssl:** add function list mac and kdf algorithms and set properties for EVP algorithm fetches [0ed8316](https://github.com/fffonion/lua-resty-openssl/commit/0ed83167dbb1b7d8171bcb59cb749187220572e2)
|
||||
- **openssl:** support FIPS in OpenSSL 3.0 [beb3ad3](https://github.com/fffonion/lua-resty-openssl/commit/beb3ad3ec8f162aeb11d3f89ea8211c2f3e38c1e)
|
||||
- **param:** add new function to use OSSL_PARAM [5ffbbcc](https://github.com/fffonion/lua-resty-openssl/commit/5ffbbcce386d98127c84b7f24bb019cff76c05e3)
|
||||
- **provider:** cipher, digest, kdf, pkey and x509 can now fetch by provider and has new get_provider_name function [52938ca](https://github.com/fffonion/lua-resty-openssl/commit/52938ca5b66f48186815975d685227836bd92cef)
|
||||
|
||||
|
||||
<a name="0.7.5"></a>
|
||||
## [0.7.5] - 2021-09-18
|
||||
### bug fixes
|
||||
- **\*:** rename some EVP_ API to use get in openssl3.0 [8fbdb39](https://github.com/fffonion/lua-resty-openssl/commit/8fbdb396d0a4988a24ff2e0404c1866a416d9cff)
|
||||
- **aux/nginx:** add 1.19.9 [eb73691](https://github.com/fffonion/lua-resty-openssl/commit/eb73691c058c9d55a1b57405f889f5bc3ecd0420)
|
||||
|
||||
|
||||
<a name="0.7.4"></a>
|
||||
## [0.7.4] - 2021-08-02
|
||||
### bug fixes
|
||||
- **extension:** fallback to ASN1_STRING_print in extension:text where X509V3_EXT_print is not available [f0268f5](https://github.com/fffonion/lua-resty-openssl/commit/f0268f55b124eb4ff65b472899e241af850f9d35)
|
||||
|
||||
|
||||
<a name="0.7.3"></a>
|
||||
## [0.7.3] - 2021-06-29
|
||||
### bug fixes
|
||||
- **pkey:** only pass in passphrase/passphrase_cb to PEM_* functions [6a56494](https://github.com/fffonion/lua-resty-openssl/commit/6a564949e08a6dbe87a44d82e694d862b77c8b68)
|
||||
- **pkey:** avoid callbacks overflow when setting passphrase_cb [e8aec4e](https://github.com/fffonion/lua-resty-openssl/commit/e8aec4e3ceb4419e373938f9ad4b592efa43acfc)
|
||||
|
||||
### features
|
||||
- **pkey:** allow to specify digest type and padding scheme in sign/verify [ff982ba](https://github.com/fffonion/lua-resty-openssl/commit/ff982ba374ab543c440ccab597d71cdbf4560cdb)
|
||||
|
||||
|
||||
<a name="0.7.2"></a>
|
||||
## [0.7.2] - 2021-03-25
|
||||
### bug fixes
|
||||
- **\*:** redefine callback functions to a style FFI will not overflow [f91202c](https://github.com/fffonion/lua-resty-openssl/commit/f91202c57b826d935d831ec452d2b90fc33277fa)
|
||||
|
||||
|
||||
<a name="0.7.1"></a>
|
||||
## [0.7.1] - 2021-03-18
|
||||
### bug fixes
|
||||
- **altname:** return unsupported as value in not implemented types [ef5e1ed](https://github.com/fffonion/lua-resty-openssl/commit/ef5e1eda9eaea1fd4c8d7d65e438275fed10cdc6)
|
||||
- **auxiliary/nginx:** typo in error message [4bd22d8](https://github.com/fffonion/lua-resty-openssl/commit/4bd22d81419ed160af1dcea16f42fd284f8f2ad5)
|
||||
|
||||
|
||||
<a name="0.7.0"></a>
|
||||
## [0.7.0] - 2021-02-19
|
||||
### bug fixes
|
||||
- **csr:** count extension count in openssl 3.0 [5af0f4b](https://github.com/fffonion/lua-resty-openssl/commit/5af0f4b02edd0fb8c461a1e08b04eb4eb781f744)
|
||||
- **csr:** BREAKING: remove csr:set_subject_alt function [513fd8a](https://github.com/fffonion/lua-resty-openssl/commit/513fd8ac61b6f7775465eabc5a3d6a454ccebc54)
|
||||
- **openssl:** include crypto header in openssl.lua [ef54bf7](https://github.com/fffonion/lua-resty-openssl/commit/ef54bf72710f2613ac6d6e5e8ebb712fa7135939)
|
||||
- **openssl:** BREAKING: not load sub modules by default [a402f05](https://github.com/fffonion/lua-resty-openssl/commit/a402f05f3ea4b85589c1de6b4347cdfc4c397ea7)
|
||||
|
||||
### features
|
||||
- **\*:** support BoringSSL [9c4e5dc](https://github.com/fffonion/lua-resty-openssl/commit/9c4e5dccefb7fa2e08c489e2922ea05e043e28f2)
|
||||
- **bn:** add generate_prime [2cc77a4](https://github.com/fffonion/lua-resty-openssl/commit/2cc77a4513dad2f4d684535d1230484e8e91bfbd)
|
||||
- **openssl:** add function to list supported cipher and digest algorithms [5bdc2a4](https://github.com/fffonion/lua-resty-openssl/commit/5bdc2a406c974f471331636de670915df9386f82)
|
||||
- **openssl:** add function to get and set fips mode [f6de183](https://github.com/fffonion/lua-resty-openssl/commit/f6de183b19e57616ded39e73518acd198c730056)
|
||||
|
||||
|
||||
<a name="0.6.11"></a>
|
||||
## [0.6.11] - 2021-01-21
|
||||
### bug fixes
|
||||
- **aux/nginx:** only show warning message when function is being called [9964a6d](https://github.com/fffonion/lua-resty-openssl/commit/9964a6d29aded1c0d06c1a8700ee313e08506c2f)
|
||||
- **openssl:** not load ssl modules by default [390ad79](https://github.com/fffonion/lua-resty-openssl/commit/390ad79c413ec779ff7a1ad2b86ff0fe389c085d)
|
||||
- **ssl:** add function to free the verify callback function [62dc81a](https://github.com/fffonion/lua-resty-openssl/commit/62dc81a4c7be1c745e7e3ab728f3e060c981f446)
|
||||
|
||||
|
||||
<a name="0.6.10"></a>
|
||||
## [0.6.10] - 2021-01-12
|
||||
### bug fixes
|
||||
- **ecx:** return nil, err in set_parameters [98acaee](https://github.com/fffonion/lua-resty-openssl/commit/98acaeeeaa60dffd93a934f4fbf7ddfd8e9e9652)
|
||||
- **pkey:** use named_curve encoding for EC group [1e65d9d](https://github.com/fffonion/lua-resty-openssl/commit/1e65d9d4b71c0e9c5f4d404e640a96e03902fd30)
|
||||
|
||||
### features
|
||||
- **pkcs12:** allow to define algorithm to encrypt key and cert [b9678ce](https://github.com/fffonion/lua-resty-openssl/commit/b9678ce4ee4a233fb0bd8ed61d41c6d45a6fbb9d)
|
||||
- **pkcs12:** check on cert and key mismatch [5953cc2](https://github.com/fffonion/lua-resty-openssl/commit/5953cc281cff06027f3b2bba23402e2915fd3ae1)
|
||||
- **pkcs12:** encode and decode for pkcs12 [1467579](https://github.com/fffonion/lua-resty-openssl/commit/1467579fbe253996570dd188f580b98b8eb1db98)
|
||||
- **pkey:** add is_private function to check if it's a private key [eb6cc1c](https://github.com/fffonion/lua-resty-openssl/commit/eb6cc1c2d5f7698c2641950d745a78da7baa6225)
|
||||
- **ssl:** add the ssl and ssl_ctx module [40f3999](https://github.com/fffonion/lua-resty-openssl/commit/40f39994446a4cb954fc516f7047194cbf1141f8)
|
||||
|
||||
|
||||
<a name="0.6.9"></a>
|
||||
## [0.6.9] - 2020-11-09
|
||||
### bug fixes
|
||||
- **\*:** not mutating tables when doing pairs to avoid missing of iterration [836d5c9](https://github.com/fffonion/lua-resty-openssl/commit/836d5c915b27c0e63782c47effae16515ba71fed)
|
||||
- **pkey:** fix typo in paramgen error message [d341246](https://github.com/fffonion/lua-resty-openssl/commit/d341246b5db5f912a3bcb06b7be1d08ffee093b3)
|
||||
- **tests:** openssl3.0 alpha7 [5caa0e6](https://github.com/fffonion/lua-resty-openssl/commit/5caa0e60193ea535d0c0f1fe8491bc6779c9e720)
|
||||
- **x509.altname:** organize GC handling better [f5a138c](https://github.com/fffonion/lua-resty-openssl/commit/f5a138c8b10dd285d9cacb6f2b3877b7831d0fba)
|
||||
|
||||
### features
|
||||
- **provider:** add the provider module [dff92af](https://github.com/fffonion/lua-resty-openssl/commit/dff92af37102b094f1187914a0c76b6635130626)
|
||||
- **x509.\*:** add get_signature_nid and get_signature_name [a35ae0a](https://github.com/fffonion/lua-resty-openssl/commit/a35ae0af6ad98251d4226e0daceab07c2832fc17)
|
||||
|
||||
|
||||
<a name="0.6.8"></a>
|
||||
## [0.6.8] - 2020-10-15
|
||||
### bug fixes
|
||||
- **pkey:** correctly free parameter after new parameters are set for RSA and DH keys on OpenSSL 1.0.2 [32d8c12](https://github.com/fffonion/lua-resty-openssl/commit/32d8c127f29e4ee0f13a8191f05f85ec74c2d8d4)
|
||||
- **tests:** sort json in tests [aeeb7c3](https://github.com/fffonion/lua-resty-openssl/commit/aeeb7c3c2c7899b1b9c36b620476cca81b8eefdc)
|
||||
|
||||
### features
|
||||
- **pkey:** allow to pass params for EC and DH keygen [e9aa7c7](https://github.com/fffonion/lua-resty-openssl/commit/e9aa7c751458134d03dfcda1318186cf3a691c1d)
|
||||
- **pkey:** get and set DH parameters [ebaad8d](https://github.com/fffonion/lua-resty-openssl/commit/ebaad8d1e6533c9ad4980f557ead986104b947d0)
|
||||
- **pkey:** support DH key and paramgen [f4661c6](https://github.com/fffonion/lua-resty-openssl/commit/f4661c6eb1d57d36daa93e8c86105b77ba8fe0cb)
|
||||
- **pkey:** support one shot signing for all key types [79ca0d4](https://github.com/fffonion/lua-resty-openssl/commit/79ca0d43feda10894bfe5f0e72c4460dd4778c66)
|
||||
|
||||
|
||||
<a name="0.6.7"></a>
|
||||
## [0.6.7] - 2020-10-08
|
||||
### features
|
||||
- **pkey:** sign_raw and verify_recover [90ed1b6](https://github.com/fffonion/lua-resty-openssl/commit/90ed1b637729bfde33a94c6467327419186bdd38)
|
||||
|
||||
|
||||
<a name="0.6.6"></a>
|
||||
## [0.6.6] - 2020-09-29
|
||||
### bug fixes
|
||||
- **\*:** export tostring for x509.name and x509.altname [6143659](https://github.com/fffonion/lua-resty-openssl/commit/6143659706ea5b8c42a418b7fac1eae4179a6280)
|
||||
- **kdf:** fix HKDF potential buffer overflow [da6f420](https://github.com/fffonion/lua-resty-openssl/commit/da6f42025c657f610f1ebee95f0489afd3628d9f)
|
||||
- **x509.name:** potential memory leak in x509.name:find() [ac51fb1](https://github.com/fffonion/lua-resty-openssl/commit/ac51fb10581ec31e639c1298c080a899466fd57d)
|
||||
- **x509.store:** return all error on load_file or add failure [a4ee237](https://github.com/fffonion/lua-resty-openssl/commit/a4ee2379802e41f5b5566ac11e59598d1f338ca5)
|
||||
|
||||
### features
|
||||
- **x509.extension:** support create by ASN.1 octet string and nconf [7d8e81f](https://github.com/fffonion/lua-resty-openssl/commit/7d8e81f6789abd951f6e6b3aeb96607f8682c1d5)
|
||||
|
||||
|
||||
<a name="0.6.5"></a>
|
||||
## [0.6.5] - 2020-09-16
|
||||
### bug fixes
|
||||
- **\*:** x509.* set should return true on success [2a09575](https://github.com/fffonion/lua-resty-openssl/commit/2a09575425133e92c990513c7ea7445cf2ca47f4)
|
||||
|
||||
|
||||
<a name="0.6.4"></a>
|
||||
## [0.6.4] - 2020-08-27
|
||||
### features
|
||||
- **x509.csr:** finish {set,add}_extension functions [d34b702](https://github.com/fffonion/lua-resty-openssl/commit/d34b702a17b4f491e2a97e971da1d6125d482066)
|
||||
- **x509.extension:** add ability to convert to other data type [15a5c7f](https://github.com/fffonion/lua-resty-openssl/commit/15a5c7ff38452a7bd04919b4a7e9c9dc1dfa931d)
|
||||
|
||||
|
||||
<a name="0.6.3"></a>
|
||||
## [0.6.3] - 2020-08-10
|
||||
### bug fixes
|
||||
- **\*:** cleanup and centralize ffi.typeof [5cbc247](https://github.com/fffonion/lua-resty-openssl/commit/5cbc2475bc5926fb0e4aa1b3e5b592144518d013)
|
||||
- **\*:** remove hack for openssl 3.0 around broken EVP_PKEY_base_id [33181c3](https://github.com/fffonion/lua-resty-openssl/commit/33181c34210fb16c4190e88e1892fb19952420b2)
|
||||
- **cipher:** use CipherFinal_ex and make test more robust [61fa022](https://github.com/fffonion/lua-resty-openssl/commit/61fa0224fc8dca8a13f9c3ae6904e6cb71c00c6b)
|
||||
- **openssl:** correctly check error for getting version num ([#6](https://github.com/fffonion/lua-resty-openssl/issues/6)) [6a4b9e6](https://github.com/fffonion/lua-resty-openssl/commit/6a4b9e636714e81d405b934868ef347b3c803674)
|
||||
- **tests:** pin lua-nginx-module and lua-resty-core [010b37e](https://github.com/fffonion/lua-resty-openssl/commit/010b37eb273da7b96ef39f95a6990357ecf49e49)
|
||||
- **tests:** make pkey parameter test less flaky [d023edc](https://github.com/fffonion/lua-resty-openssl/commit/d023edcba56e5832b04e2ee0d84195c69a6258d4)
|
||||
- **x509.\*:** pass correct digest parameter to sign [982ad48](https://github.com/fffonion/lua-resty-openssl/commit/982ad48594444994d5c5b98ba9ca3d139ce96f8c)
|
||||
|
||||
### features
|
||||
- **\*:** support reset for hmac and digest [37ba4b0](https://github.com/fffonion/lua-resty-openssl/commit/37ba4b0f63c60898ee25cfeeeab8b5651c62296e)
|
||||
- **\*:** initial support for OpenSSL 3.0 [be5dc10](https://github.com/fffonion/lua-resty-openssl/commit/be5dc10c24aabb6697ecb9fe2bd75c8a11e2b2d7)
|
||||
- **x509.csr:** add get_extension and get_extensions function [638ca46](https://github.com/fffonion/lua-resty-openssl/commit/638ca46ecf1a4fdacac6e24abaea7d19db93c98b)
|
||||
- **x509.extensions:** finish the stack implementation [f4cf725](https://github.com/fffonion/lua-resty-openssl/commit/f4cf7256e9cce0a280fab46d356ca5fcf3a48b4f)
|
||||
- **x509.revoked:** add the x509.revoked module [58f0ce1](https://github.com/fffonion/lua-resty-openssl/commit/58f0ce11f2a39cdaabf1c9ba38ea7587adf8f25a)
|
||||
|
||||
|
||||
<a name="0.6.2"></a>
|
||||
## [0.6.2] - 2020-05-13
|
||||
### bug fixes
|
||||
- **\*:** add prefix to all error messages [8f52c25](https://github.com/fffonion/lua-resty-openssl/commit/8f52c2583b87ae0e66e9546f5db03d8fe667cbd4)
|
||||
|
||||
### features
|
||||
- **cipher:** AEAD modes with authentication [fd7471e](https://github.com/fffonion/lua-resty-openssl/commit/fd7471e3a011519df0250681ee1bf82d61b1f154)
|
||||
- **pkey:** support one shot sign/verify for Ed25519 and Ed448 keys [2565e85](https://github.com/fffonion/lua-resty-openssl/commit/2565e85337325f9cee7d601220120b185a22c430)
|
||||
- **pkey:** support key derivation for EC, X25519 and X448 keys [0c0d941](https://github.com/fffonion/lua-resty-openssl/commit/0c0d9417711f4c9b513ae02382ea6f9f68f750fd)
|
||||
- **pkey:** output pkey to DER and JWK format [8da24a5](https://github.com/fffonion/lua-resty-openssl/commit/8da24a5cd9241c09f51c610164dee5daffdd9129)
|
||||
- **pkey:** load EC key from JWK format [df0c06f](https://github.com/fffonion/lua-resty-openssl/commit/df0c06f1e07be3c6e46d9d2a86005361ad386f83)
|
||||
- **pkey:** set/get_parameters for EC key [67d54c8](https://github.com/fffonion/lua-resty-openssl/commit/67d54c8dc8555870bbf3fb216b3c636f3d9b220d)
|
||||
- **pkey:** load RSA key from JWK format [dc118b3](https://github.com/fffonion/lua-resty-openssl/commit/dc118b3aec2a9ff26fc3f615a1569525cbc13dd4)
|
||||
- **pkey:** add function to set rsa parameter [867fa10](https://github.com/fffonion/lua-resty-openssl/commit/867fa109863a2fd770f26a44b15cbea9d422b5cb)
|
||||
|
||||
|
||||
<a name="0.6.1"></a>
|
||||
## [0.6.1] - 2020-05-08
|
||||
### bug fixes
|
||||
- **x509:** fail soft when CRL is not set [2f2eb5e](https://github.com/fffonion/lua-resty-openssl/commit/2f2eb5edc78e3aa892eb36bd1b091c42ddc64480)
|
||||
|
||||
|
||||
<a name="0.6.0"></a>
|
||||
## [0.6.0] - 2020-03-11
|
||||
### features
|
||||
- **bn:** mathematics, bit shift and comparasion operations [87bf557](https://github.com/fffonion/lua-resty-openssl/commit/87bf5575a3643e11814b9c7be68ec78ce05011fe)
|
||||
- **kdf:** use give id as type parameter [0e767d0](https://github.com/fffonion/lua-resty-openssl/commit/0e767d006f4561788d826eef82b753093f06ef9e)
|
||||
- **kdf:** kdf.derive in luaossl compat mode [45788b6](https://github.com/fffonion/lua-resty-openssl/commit/45788b6ea742755b31d6b361950f3ea5d5d24bdf)
|
||||
|
||||
|
||||
<a name="0.6.0-rc.0"></a>
|
||||
## [0.6.0-rc.0] - 2020-03-02
|
||||
### features
|
||||
- **altname:** RFC822 alias to email [37467fc](https://github.com/fffonion/lua-resty-openssl/commit/37467fcf83093d0c99251f43a4cc916d5c934eda)
|
||||
- **kdf:** add key derivation functions support [d78835e](https://github.com/fffonion/lua-resty-openssl/commit/d78835e861df4b7f79bb0fe5e17a2f19be1e0d3f)
|
||||
|
||||
|
||||
<a name="0.5.4"></a>
|
||||
## [0.5.4] - 2020-02-27
|
||||
### bug fixes
|
||||
- **store:** set X509_V_FLAG_CRL_CHECK flag if a crl is added [88574d5](https://github.com/fffonion/lua-resty-openssl/commit/88574d5ecef0f75a293cd7d23b764d629905e3df)
|
||||
- **x509.\*:** returns soft error if extension is not found [a0a75aa](https://github.com/fffonion/lua-resty-openssl/commit/a0a75aa2644203e22461aa1dd09ef8672e2ba576)
|
||||
|
||||
|
||||
<a name="0.5.3"></a>
|
||||
## [0.5.3] - 2020-02-22
|
||||
### features
|
||||
- **openssl:** lua-resty-hmac compat [fad844f](https://github.com/fffonion/lua-resty-openssl/commit/fad844f804abe8d73b7d4b7655d562fdb3d84ebf)
|
||||
|
||||
|
||||
<a name="0.5.2"></a>
|
||||
## [0.5.2] - 2020-02-09
|
||||
### bug fixes
|
||||
- **pkey:** decrease copy by 1 when generating key [bcc38e9](https://github.com/fffonion/lua-resty-openssl/commit/bcc38e9fc5e733a8f3f9d09e5eef1e2eb3c15d4d)
|
||||
|
||||
### features
|
||||
- **x509.extension:** allow to create an extension by NID [6d66a2d](https://github.com/fffonion/lua-resty-openssl/commit/6d66a2d9fa7cc36cc2e6c85a78ad2236e525f3b0)
|
||||
|
||||
|
||||
<a name="0.5.1"></a>
|
||||
## [0.5.1] - 2020-02-04
|
||||
### bug fixes
|
||||
- **x509.crl:** fix creating empty crl instance [046ca36](https://github.com/fffonion/lua-resty-openssl/commit/046ca36228f639c191c81a7b84dfedfc523d0340)
|
||||
|
||||
### features
|
||||
- **pkey:** load encrypted PEM key [7fa7a29](https://github.com/fffonion/lua-resty-openssl/commit/7fa7a29882bbcef294f83cd1f66b9960344a0e07)
|
||||
- **x509.extension:** add tostring() as synonym to text() [87c162d](https://github.com/fffonion/lua-resty-openssl/commit/87c162de9fa7bb3e3930bd760ff7dfece30f1b49)
|
||||
|
||||
|
||||
<a name="0.5.0"></a>
|
||||
## [0.5.0] - 2020-02-03
|
||||
### bug fixes
|
||||
- **\*:** add missing crl.dup function, organize store:add gc handler [6815e5d](https://github.com/fffonion/lua-resty-openssl/commit/6815e5df04fdb77c83b0345f166664759a573962)
|
||||
- **asn1:** support GENERALIZEDTIME string format [8c7e2d6](https://github.com/fffonion/lua-resty-openssl/commit/8c7e2d67857cb6875cf52fadf43cadf05d8c5c40)
|
||||
- **error:** return latest error string not earliest in some cases [0b5955d](https://github.com/fffonion/lua-resty-openssl/commit/0b5955d4cb73f3c7d3321ed7384ae862640a6a7f)
|
||||
- **stack:** protective over first argument [bf455ff](https://github.com/fffonion/lua-resty-openssl/commit/bf455ff310b94b26a3bed513ffc9f308f65691ed)
|
||||
- **x509:** guard around oscp stack index [1b59b85](https://github.com/fffonion/lua-resty-openssl/commit/1b59b8565b5dee4cb1dd14d22bc24ec04dfbf3d6)
|
||||
- **x509.store:** correctly save x509 instance references [d8d755f](https://github.com/fffonion/lua-resty-openssl/commit/d8d755f7a281ad09d896a1d78ad9e53f6c028bdc)
|
||||
|
||||
### features
|
||||
- **\*:** add iterater and helpers for stack-like objects [46bb723](https://github.com/fffonion/lua-resty-openssl/commit/46bb7237028a16e67878d8310c25e908ceece009)
|
||||
- **autogen:** generate tests for x509, csr and crl [1392428](https://github.com/fffonion/lua-resty-openssl/commit/1392428352164d2a1a6e0c03075ff65b55aecdee)
|
||||
- **objects:** add helper function for ASN1_OBJECT [d037706](https://github.com/fffonion/lua-resty-openssl/commit/d037706c11d716afe3616bdaf4658afc1763081d)
|
||||
- **pkey:** asymmetric encryption and decryption [6d60451](https://github.com/fffonion/lua-resty-openssl/commit/6d60451157edbf9cefb634f888dfa3e6d9be302f)
|
||||
- **x509:** getter/setters for extensions [243f40d](https://github.com/fffonion/lua-resty-openssl/commit/243f40d35562a516f404188a5c7eb8f5134d9b30)
|
||||
- **x509:** add get_ocsp_url and get_crl_url [6141b6f](https://github.com/fffonion/lua-resty-openssl/commit/6141b6f5aed38706b477a71d8c4383bf55da7eee)
|
||||
- **x509.altname:** support iterate and decode over the stack [083a201](https://github.com/fffonion/lua-resty-openssl/commit/083a201746e02d51f6c5c640ad9bf8c6730ebe0b)
|
||||
- **x509.crl:** add crl module [242f8cb](https://github.com/fffonion/lua-resty-openssl/commit/242f8cb45d6c2df5918f26540c92a430d42feb5d)
|
||||
- **x509.csr:** autogen some csr functions as well [9800e36](https://github.com/fffonion/lua-resty-openssl/commit/9800e36c2ff8a299b88f24091cc722940a8652bb)
|
||||
- **x509.extension:** decode object, set/get critical flag and get text representation [8cb585f](https://github.com/fffonion/lua-resty-openssl/commit/8cb585fc51de04065cd7eeeea06e6240e7251614)
|
||||
- **x509.extension:** add x509.extension.dist_points and x509.extension.info_access [63d3992](https://github.com/fffonion/lua-resty-openssl/commit/63d3992163144ed75474a8046398d605570c30b7)
|
||||
|
||||
|
||||
<a name="0.4.4"></a>
|
||||
## [0.4.4] - 2020-02-27
|
||||
### bug fixes
|
||||
- **pkey:** clean up errors when trying loading key types [7b3d351](https://github.com/fffonion/lua-resty-openssl/commit/7b3d3513cfb7a8800f49dbdd3ca521b4dadefbad)
|
||||
|
||||
|
||||
<a name="0.4.3"></a>
|
||||
## [0.4.3] - 2020-01-15
|
||||
### bug fixes
|
||||
- **asn1:** support GENERALIZEDTIME string format [cc6326f](https://github.com/fffonion/lua-resty-openssl/commit/cc6326fed1bc53e64042d4742208ed68d7bb42ac)
|
||||
|
||||
|
||||
<a name="0.4.2"></a>
|
||||
## [0.4.2] - 2020-01-06
|
||||
### bug fixes
|
||||
- **bn:** memory leak in bn:to_hex [6718e9e](https://github.com/fffonion/lua-resty-openssl/commit/6718e9e76a8410c78b32e5abf6d06a628fe8dc8b)
|
||||
- **compat:** refine luaossl compat mode [0d86eb5](https://github.com/fffonion/lua-resty-openssl/commit/0d86eb58848e970408bec7ee9d77102c241c3a5c)
|
||||
- **openssl:** typo in luaossl_compat [#1](https://github.com/fffonion/lua-resty-openssl/issues/1) [1c3ea60](https://github.com/fffonion/lua-resty-openssl/commit/1c3ea60877d1532eaaddc13ab3be1550c4c5a7f1)
|
||||
- **x509:** memory leak in x509:set_not_(before|after) [b4a32f8](https://github.com/fffonion/lua-resty-openssl/commit/b4a32f82c33107d2db729caa06aee141b7f9a016)
|
||||
- **x509:** and missing x509.get_serial_number code [e7d0fb6](https://github.com/fffonion/lua-resty-openssl/commit/e7d0fb6eace77d357d19043b88bb765ec29a5193)
|
||||
- **x509.csr:** correctly gc extension [ece5be3](https://github.com/fffonion/lua-resty-openssl/commit/ece5be3f517b69563150973e7da6063d5826a9ad)
|
||||
- **x509.store:** memory leak in store:add [57815dd](https://github.com/fffonion/lua-resty-openssl/commit/57815dd38bbb2e260e8cdf3e8ddac48d6254b8fc)
|
||||
|
||||
|
||||
<a name="0.4.1"></a>
|
||||
## [0.4.1] - 2019-12-24
|
||||
### bug fixes
|
||||
- **x509:** correct X509_add1_ext_i2d include path [b08b312](https://github.com/fffonion/lua-resty-openssl/commit/b08b3123a0fb2770296f04c830414bd38588e8eb)
|
||||
|
||||
### features
|
||||
- **x509:** getters for basic constraints and basic constraints critical [82f5725](https://github.com/fffonion/lua-resty-openssl/commit/82f5725d4738b3bf83fcbf3154fe5979fe8d1af4)
|
||||
|
||||
|
||||
<a name="0.4.0"></a>
|
||||
## [0.4.0] - 2019-12-20
|
||||
### bug fixes
|
||||
- **\*:** always return ok, err if there's no explict return value [3e68167](https://github.com/fffonion/lua-resty-openssl/commit/3e681676f85e26c8c7af6f72a2c4afcb98952cd6)
|
||||
- **evp:** correct ptr naming [72f8765](https://github.com/fffonion/lua-resty-openssl/commit/72f8765250861d6504a767da81afe19c2d2896a4)
|
||||
|
||||
### features
|
||||
- **\*:** add x509.digest and bn.to_hex [11ea9ae](https://github.com/fffonion/lua-resty-openssl/commit/11ea9aebca6bb5c354ad94525bd2e264debfebbd)
|
||||
- **version:** add function to print human readable version [7687573](https://github.com/fffonion/lua-resty-openssl/commit/76875731011e5641eef9881ace2becf1bf057cfd)
|
||||
- **x509:** add x509 stack (chain) support [72154fc](https://github.com/fffonion/lua-resty-openssl/commit/72154fcb7686ce5a754d4fe4f121f07507a1513e)
|
||||
- **x509.chain:** allow to duplicate a stack [3fa19b7](https://github.com/fffonion/lua-resty-openssl/commit/3fa19b79509c73cf5dce6e3445cbf90a9466d656)
|
||||
- **x509.name:** allow to iterate over objects and find objects [714a1e5](https://github.com/fffonion/lua-resty-openssl/commit/714a1e541e0ce3ffb33d257d9af50ae628094fb2)
|
||||
- **x509.store:** support certificate verification [c9dd4bf](https://github.com/fffonion/lua-resty-openssl/commit/c9dd4bf8065a51a97fcf940c33ba046b73ac2049)
|
||||
|
||||
|
||||
<a name="0.3.0"></a>
|
||||
## [0.3.0] - 2019-12-12
|
||||
### bug fixes
|
||||
- **\*:** move cdef and macros to seperate file [28c3390](https://github.com/fffonion/lua-resty-openssl/commit/28c339085383bfbcb72e192701b96e08fb4344f0)
|
||||
- **\*:** normalize error handling [ff18d54](https://github.com/fffonion/lua-resty-openssl/commit/ff18d54d2b4402de3bc02731f99c32a9953f8784)
|
||||
|
||||
### features
|
||||
- **cipher:** add symmetric cryptography support [9b89e8d](https://github.com/fffonion/lua-resty-openssl/commit/9b89e8dcc1489832c893373150bfeef6a838da34)
|
||||
- **hmac:** add hmac support [5cc2a15](https://github.com/fffonion/lua-resty-openssl/commit/5cc2a15ce43a9c1c73dccf1a15232ee2a9108460)
|
||||
|
||||
|
||||
<a name="0.2.1"></a>
|
||||
## [0.2.1] - 2019-10-22
|
||||
### bug fixes
|
||||
- **x509:** decrease by set_version by 1 per standard [b6ea5b9](https://github.com/fffonion/lua-resty-openssl/commit/b6ea5b933aadfb8284f7486eb33d8a4c21b7a6de)
|
||||
|
||||
|
||||
<a name="0.2.0"></a>
|
||||
## 0.2.0 - 2019-10-18
|
||||
### bug fixes
|
||||
- **\*:** fix working and name test [f6db7ef](https://github.com/fffonion/lua-resty-openssl/commit/f6db7ef3c1ce5f9a75f01dc24f904fd8942c7897)
|
||||
- **\*:** normalize naming, explictly control cdef for different openssl versions [c626b53](https://github.com/fffonion/lua-resty-openssl/commit/c626b538c2dc33272b130503ddd21f21bd9d995f)
|
||||
- **\*:** cleanup cdef [3c02d02](https://github.com/fffonion/lua-resty-openssl/commit/3c02d020822a30fdf7dae0aa7c6aa47c4660aea8)
|
||||
- **\*:** test cdata type before passing in ffi [de99069](https://github.com/fffonion/lua-resty-openssl/commit/de99069e40c075844a15b91720e2d5c9c9a68dd7)
|
||||
|
||||
### features
|
||||
- **\*:** add more x509 API, and rand bytes generator [6630fde](https://github.com/fffonion/lua-resty-openssl/commit/6630fde2e5e9f367e4652dc390678d4eeb57ad5d)
|
||||
- **error:** add ability to pull error description [d19ece9](https://github.com/fffonion/lua-resty-openssl/commit/d19ece993ac797fdf6708400cf83e3f4ed0bb9f4)
|
||||
- **x509:** generate certificate [9b4f59b](https://github.com/fffonion/lua-resty-openssl/commit/9b4f59bf94647aab37da6b8076ee99e155ba8023)
|
||||
- **x509:** export pubkey [ede4f81](https://github.com/fffonion/lua-resty-openssl/commit/ede4f817cb0fe092ad6f9ab5d6ecdcde864a9fd8)
|
||||
|
||||
|
||||
[Unreleased]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.21...HEAD
|
||||
[0.8.21]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.20...0.8.21
|
||||
[0.8.20]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.19...0.8.20
|
||||
[0.8.19]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.18...0.8.19
|
||||
[0.8.18]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.17...0.8.18
|
||||
[0.8.17]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.16...0.8.17
|
||||
[0.8.16]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.15...0.8.16
|
||||
[0.8.15]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.14...0.8.15
|
||||
[0.8.14]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.13...0.8.14
|
||||
[0.8.13]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.11...0.8.13
|
||||
[0.8.11]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.10...0.8.11
|
||||
[0.8.10]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.9...0.8.10
|
||||
[0.8.9]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.8...0.8.9
|
||||
[0.8.8]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.7...0.8.8
|
||||
[0.8.7]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.6...0.8.7
|
||||
[0.8.6]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.5...0.8.6
|
||||
[0.8.5]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.4...0.8.5
|
||||
[0.8.4]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.3...0.8.4
|
||||
[0.8.3]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.2...0.8.3
|
||||
[0.8.2]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.1...0.8.2
|
||||
[0.8.1]: https://github.com/fffonion/lua-resty-openssl/compare/0.8.0...0.8.1
|
||||
[0.8.0]: https://github.com/fffonion/lua-resty-openssl/compare/0.7.5...0.8.0
|
||||
[0.7.5]: https://github.com/fffonion/lua-resty-openssl/compare/0.7.4...0.7.5
|
||||
[0.7.4]: https://github.com/fffonion/lua-resty-openssl/compare/0.7.3...0.7.4
|
||||
[0.7.3]: https://github.com/fffonion/lua-resty-openssl/compare/0.7.2...0.7.3
|
||||
[0.7.2]: https://github.com/fffonion/lua-resty-openssl/compare/0.7.1...0.7.2
|
||||
[0.7.1]: https://github.com/fffonion/lua-resty-openssl/compare/0.7.0...0.7.1
|
||||
[0.7.0]: https://github.com/fffonion/lua-resty-openssl/compare/0.6.11...0.7.0
|
||||
[0.6.11]: https://github.com/fffonion/lua-resty-openssl/compare/0.6.10...0.6.11
|
||||
[0.6.10]: https://github.com/fffonion/lua-resty-openssl/compare/0.6.9...0.6.10
|
||||
[0.6.9]: https://github.com/fffonion/lua-resty-openssl/compare/0.6.8...0.6.9
|
||||
[0.6.8]: https://github.com/fffonion/lua-resty-openssl/compare/0.6.7...0.6.8
|
||||
[0.6.7]: https://github.com/fffonion/lua-resty-openssl/compare/0.6.6...0.6.7
|
||||
[0.6.6]: https://github.com/fffonion/lua-resty-openssl/compare/0.6.5...0.6.6
|
||||
[0.6.5]: https://github.com/fffonion/lua-resty-openssl/compare/0.6.4...0.6.5
|
||||
[0.6.4]: https://github.com/fffonion/lua-resty-openssl/compare/0.6.3...0.6.4
|
||||
[0.6.3]: https://github.com/fffonion/lua-resty-openssl/compare/0.6.2...0.6.3
|
||||
[0.6.2]: https://github.com/fffonion/lua-resty-openssl/compare/0.6.1...0.6.2
|
||||
[0.6.1]: https://github.com/fffonion/lua-resty-openssl/compare/0.6.0...0.6.1
|
||||
[0.6.0]: https://github.com/fffonion/lua-resty-openssl/compare/0.6.0-rc.0...0.6.0
|
||||
[0.6.0-rc.0]: https://github.com/fffonion/lua-resty-openssl/compare/0.5.4...0.6.0-rc.0
|
||||
[0.5.4]: https://github.com/fffonion/lua-resty-openssl/compare/0.5.3...0.5.4
|
||||
[0.5.3]: https://github.com/fffonion/lua-resty-openssl/compare/0.5.2...0.5.3
|
||||
[0.5.2]: https://github.com/fffonion/lua-resty-openssl/compare/0.5.1...0.5.2
|
||||
[0.5.1]: https://github.com/fffonion/lua-resty-openssl/compare/0.5.0...0.5.1
|
||||
[0.5.0]: https://github.com/fffonion/lua-resty-openssl/compare/0.4.4...0.5.0
|
||||
[0.4.4]: https://github.com/fffonion/lua-resty-openssl/compare/0.4.3...0.4.4
|
||||
[0.4.3]: https://github.com/fffonion/lua-resty-openssl/compare/0.4.2...0.4.3
|
||||
[0.4.2]: https://github.com/fffonion/lua-resty-openssl/compare/0.4.1...0.4.2
|
||||
[0.4.1]: https://github.com/fffonion/lua-resty-openssl/compare/0.4.0...0.4.1
|
||||
[0.4.0]: https://github.com/fffonion/lua-resty-openssl/compare/0.3.0...0.4.0
|
||||
[0.3.0]: https://github.com/fffonion/lua-resty-openssl/compare/0.2.1...0.3.0
|
||||
[0.2.1]: https://github.com/fffonion/lua-resty-openssl/compare/0.2.0...0.2.1
|
|
@ -0,0 +1,25 @@
|
|||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2020, Wangchong Zhou
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,18 @@
|
|||
OPENRESTY_PREFIX=/usr/local/openresty
|
||||
|
||||
#LUA_VERSION := 5.1
|
||||
PREFIX ?= /usr/local
|
||||
LUA_INCLUDE_DIR ?= $(PREFIX)/include
|
||||
LUA_LIB_DIR ?= $(PREFIX)/lib/lua/$(LUA_VERSION)
|
||||
|
||||
.PHONY: all test install
|
||||
|
||||
all: ;
|
||||
|
||||
install: all
|
||||
cp -rpv lib/resty/openssl/. $(DESTDIR)$(LUA_LIB_DIR)/resty/openssl
|
||||
|
||||
test: all
|
||||
PATH=$(OPENRESTY_PREFIX)/nginx/sbin:$$PATH prove -I../test-nginx/lib -r t
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,11 @@
|
|||
name = lua-resty-openssl
|
||||
abstract = FFI-based OpenSSL binding for LuaJIT
|
||||
author = fffonion
|
||||
is_original = yes
|
||||
license = 3bsd
|
||||
lib_dir = lib
|
||||
doc_dir = lib
|
||||
repo_link = https://github.com/fffonion/lua-resty-openssl
|
||||
main_module = lib/resty/openssl.lua
|
||||
requires = luajit
|
||||
exclude_files=*.rock, *.rockspec
|
|
@ -0,0 +1,110 @@
|
|||
local key = string.rep("0", 32)
|
||||
local iv = string.rep("0", 12)
|
||||
|
||||
local to_be_encrypted = "secret"
|
||||
|
||||
local aad = "aead aad"
|
||||
|
||||
local mode = "aes-256-gcm"
|
||||
-- local mode = "chacha20-poly1305"
|
||||
ngx.say("use cipher ", mode)
|
||||
|
||||
-- using one shot interface
|
||||
local cipher = assert(require("resty.openssl.cipher").new(mode))
|
||||
local encrypted = assert(cipher:encrypt(key, iv, to_be_encrypted, false, aad))
|
||||
-- OR using streaming interface
|
||||
assert(cipher:init(key, iv, {
|
||||
is_encrypt = true,
|
||||
}))
|
||||
assert(cipher:update_aead_aad(aad))
|
||||
encrypted = assert(cipher:final(to_be_encrypted))
|
||||
|
||||
ngx.say("encryption result: ", ngx.encode_base64(encrypted))
|
||||
|
||||
local tag = assert(cipher:get_aead_tag())
|
||||
|
||||
ngx.say("tag is: ", ngx.encode_base64(tag), " ", #tag)
|
||||
|
||||
local _, err = cipher:decrypt(key, iv, encrypted, false, nil, tag)
|
||||
if err then
|
||||
ngx.say("no AAD, decryption failed")
|
||||
end
|
||||
|
||||
local _, err = cipher:decrypt(key, iv, encrypted, false, "wrong", tag)
|
||||
if err then
|
||||
ngx.say("wrong AAD, decryption failed")
|
||||
end
|
||||
|
||||
-- this seems not working for chacha20-poly1305
|
||||
local _, err = cipher:decrypt(key, iv, encrypted, false, aad, nil)
|
||||
if err then
|
||||
ngx.say("no tag, decryption failed")
|
||||
end
|
||||
|
||||
local _, err = cipher:decrypt(key, iv, encrypted, false, aad, "wrong")
|
||||
if err then
|
||||
ngx.say("wrong tag, decryption failed")
|
||||
end
|
||||
|
||||
-- using one shot interface
|
||||
local decrypted = assert(cipher:decrypt(key, iv, encrypted, false, aad, tag))
|
||||
-- OR using streaming interface
|
||||
assert(cipher:init(key, iv, {
|
||||
is_encrypt = false,
|
||||
}))
|
||||
assert(cipher:update_aead_aad(aad))
|
||||
assert(cipher:set_aead_tag(tag))
|
||||
decrypted = assert(cipher:final(encrypted))
|
||||
|
||||
ngx.say("decryption result: ", decrypted)
|
||||
|
||||
--[[
|
||||
Note in some implementations like `libsodium` or Java, AEAD ciphers append the `tag` (or `MAC`)
|
||||
at the end of encrypted ciphertext. In such case, user will need to manually cut off the `tag`
|
||||
with correct size(usually 16 bytes) and pass in the ciphertext and `tag` seperately.
|
||||
|
||||
-- encrypt with libsodium and decrypt in lua-resty-openssl
|
||||
|
||||
<? php
|
||||
$encrypted_with_tag = sodium_crypto_aead_aes256gcm_encrypt(
|
||||
$to_be_encrypted,
|
||||
$aad,
|
||||
$iv,
|
||||
$key
|
||||
);
|
||||
?>
|
||||
|
||||
local tag = string.sub(encrypted_with_tag, #encrypted_with_tag-16, #encrypted_with_tag)
|
||||
local encrypted = string.sub(encrypted_with_tag, 1, #encrypted_with_tag-16)
|
||||
local decrypted = assert(cipher:decrypt(key, iv, encrypted, false, aad, tag))
|
||||
|
||||
|
||||
-- encrypt with lua-resty-openssl and decrypt in libsodium
|
||||
|
||||
local encrypted = assert(cipher:encrypt(key, iv, to_be_encrypted, false, aad))
|
||||
local tag = assert(cipher:get_aead_tag())
|
||||
|
||||
<? php
|
||||
$decrypted = sodium_crypto_aead_aes256gcm_decrypt(
|
||||
$encrypted . $tag,
|
||||
$aad,
|
||||
$iv,
|
||||
$key
|
||||
);
|
||||
?>
|
||||
|
||||
]]--
|
||||
|
||||
--[[
|
||||
If the encryption is not done properly, it's possible that no tag is provided after all.
|
||||
In such case, use the streaming interface and call update() instead of final()
|
||||
]]
|
||||
|
||||
assert(cipher:init(key, iv, {
|
||||
is_encrypt = false,
|
||||
}))
|
||||
assert(cipher:update_aead_aad(aad))
|
||||
decrypted = assert(cipher:update(encrypted))
|
||||
|
||||
ngx.say("decryption result (without checking MAC): ", decrypted)
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
|
||||
-- sample function to generate a DER CSR from given pkey and domains
|
||||
local function create_csr(domain_pkey, ...)
|
||||
local domains = {...}
|
||||
|
||||
local subject = require("resty.openssl.x509.name").new()
|
||||
local _, err = subject:add("CN", domains[1])
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local alt, err
|
||||
if #{...} > 1 then
|
||||
alt, err = require("resty.openssl.x509.altname").new()
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
for _, domain in pairs(domains) do
|
||||
_, err = alt:add("DNS", domain)
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local csr = require("resty.openssl.x509.csr").new()
|
||||
local _
|
||||
_, err = csr:set_subject_name(subject)
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
if alt then
|
||||
_, err = csr:set_subject_alt_name(alt)
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
_, err = csr:set_pubkey(domain_pkey)
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
_, err = csr:sign(domain_pkey)
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return csr:tostring("DER"), nil
|
||||
end
|
||||
|
||||
-- create a EC key
|
||||
local pkey, err = require("resty.openssl.pkey").new({
|
||||
type = 'EC',
|
||||
curve = 'prime256v1',
|
||||
})
|
||||
if err then
|
||||
error(err)
|
||||
end
|
||||
|
||||
-- create a CSR using the key
|
||||
local der, err = create_csr(pkey, "example.com", "*.example.com")
|
||||
if err then
|
||||
error(err)
|
||||
end
|
||||
|
||||
-- use openssl cli to see csr we just generated
|
||||
local f = io.open("example.csr", "w")
|
||||
f:write(der)
|
||||
f:close()
|
||||
os.execute("openssl req -in example.csr -inform der -noout -text")
|
||||
os.remove("example.csr")
|
|
@ -0,0 +1,52 @@
|
|||
local version=require "resty.openssl.version"
|
||||
|
||||
print("VERSION:")
|
||||
|
||||
local version_table = {
|
||||
"VERSION",
|
||||
"CFLAGS",
|
||||
"BUILT_ON",
|
||||
"PLATFORM",
|
||||
"DIR",
|
||||
"ENGINES_DIR",
|
||||
"VERSION_STRING",
|
||||
"FULL_VERSION_STRING",
|
||||
"MODULES_DIR",
|
||||
"CPU_INFO",
|
||||
}
|
||||
|
||||
for _, k in ipairs(version_table) do
|
||||
print(string.format("%20s: %s", k, version.version(version[k])))
|
||||
end
|
||||
|
||||
print(string.rep("-", 64))
|
||||
|
||||
if version.OPENSSL_3X then
|
||||
|
||||
print("INFO:")
|
||||
local info_table = {
|
||||
"INFO_CONFIG_DIR",
|
||||
"INFO_ENGINES_DIR",
|
||||
"INFO_MODULES_DIR",
|
||||
"INFO_DSO_EXTENSION",
|
||||
"INFO_DIR_FILENAME_SEPARATOR",
|
||||
"INFO_LIST_SEPARATOR",
|
||||
"INFO_SEED_SOURCE",
|
||||
"INFO_CPU_SETTINGS",
|
||||
}
|
||||
|
||||
for _, k in ipairs(info_table) do
|
||||
print(string.format("%20s: %s", k, version.info(version[k])))
|
||||
end
|
||||
|
||||
print(string.rep("-", 64))
|
||||
|
||||
print("PROVIDER:")
|
||||
local pro = require "resty.openssl.provider"
|
||||
|
||||
for _, n in ipairs({"default", "legacy", "fips", "null"}) do
|
||||
local ok, err = pro.load(n)
|
||||
print(string.format("%10s load: %s", n, ok or err))
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
local pkey = require("resty.openssl.pkey")
|
||||
|
||||
local priv = assert(pkey.new())
|
||||
local pub = assert(pkey.new(priv:to_PEM("public")))
|
||||
|
||||
local original = "original text"
|
||||
|
||||
-- same as nodejs: crypto.privateEncrypt
|
||||
-- php: openssl_private_encrypt
|
||||
local digested = assert(priv:sign_raw(original))
|
||||
|
||||
print("Digested message: " .. ngx.encode_base64(digested))
|
||||
|
||||
-- same as nodejs: crypto.publicDecrypt
|
||||
-- php: openssl_public_decrypt
|
||||
local recovered = assert(pub:verify_recover(digested))
|
||||
print("Recovered message: " .. recovered)
|
|
@ -0,0 +1,76 @@
|
|||
local openssl_bignum = require "resty.openssl.bn"
|
||||
local openssl_rand = require "resty.openssl.rand"
|
||||
local openssl_pkey = require "resty.openssl.pkey"
|
||||
local x509 = require "resty.openssl.x509"
|
||||
local x509_extension = require "resty.openssl.x509.extension"
|
||||
local x509_name = require "resty.openssl.x509.name"
|
||||
|
||||
-- taken from https://github.com/Kong/kong/blob/master/kong/cmd/utils/prefix_handler.lua
|
||||
local function generate_self_signed()
|
||||
local key = openssl_pkey.new { bits = 2048 }
|
||||
|
||||
local crt = x509.new()
|
||||
assert(crt:set_pubkey(key))
|
||||
assert(crt:set_version(3))
|
||||
assert(crt:set_serial_number(openssl_bignum.from_binary(openssl_rand.bytes(16))))
|
||||
|
||||
-- last for 20 years
|
||||
local now = os.time()
|
||||
assert(crt:set_not_before(now))
|
||||
assert(crt:set_not_after(now + 86400 * 20 * 365))
|
||||
|
||||
local name = assert(x509_name.new()
|
||||
:add("C", "US")
|
||||
:add("ST", "California")
|
||||
:add("L", "San Francisco")
|
||||
:add("O", "Kong")
|
||||
:add("OU", "IT Department")
|
||||
:add("CN", "localhost"))
|
||||
|
||||
assert(crt:set_subject_name(name))
|
||||
assert(crt:set_issuer_name(name))
|
||||
|
||||
-- Not a CA
|
||||
assert(crt:set_basic_constraints { CA = false })
|
||||
assert(crt:set_basic_constraints_critical(true))
|
||||
|
||||
-- Only allowed to be used for TLS connections (client or server)
|
||||
assert(crt:add_extension(x509_extension.new("extendedKeyUsage",
|
||||
"serverAuth,clientAuth")))
|
||||
|
||||
-- RFC-3280 4.2.1.2
|
||||
assert(crt:add_extension(x509_extension.new("subjectKeyIdentifier", "hash", {
|
||||
subject = crt
|
||||
})))
|
||||
|
||||
-- All done; sign
|
||||
assert(crt:sign(key))
|
||||
|
||||
return crt, key
|
||||
end
|
||||
|
||||
|
||||
local crt, key = generate_self_signed()
|
||||
|
||||
do -- write key out
|
||||
local fd = assert(io.open("key.pem", "w+b"))
|
||||
local pem = assert(key:to_PEM("private"))
|
||||
assert(fd:write(pem))
|
||||
fd:close()
|
||||
end
|
||||
|
||||
print("================== private key =================")
|
||||
os.execute("openssl pkey -in key.pem -noout -text")
|
||||
os.remove("key.pem")
|
||||
|
||||
do -- write cert out
|
||||
local fd = assert(io.open("cert.pem", "w+b"))
|
||||
local pem = assert(crt:to_PEM("private"))
|
||||
assert(fd:write(pem))
|
||||
fd:close()
|
||||
end
|
||||
|
||||
print("\n\n")
|
||||
print("================== certificate =================")
|
||||
os.execute("openssl x509 -in cert.pem -noout -text")
|
||||
os.remove("cert.pem")
|
|
@ -0,0 +1,58 @@
|
|||
local pkey = require("resty.openssl.pkey")
|
||||
local digest = require("resty.openssl.digest")
|
||||
local x509 = require("resty.openssl.x509")
|
||||
local altname = require("resty.openssl.x509.altname")
|
||||
local extension = require("resty.openssl.x509.extension")
|
||||
local objects = require("resty.openssl.objects")
|
||||
|
||||
-- creates the ACME Identifier NID into openssl's internal lookup table
|
||||
-- if it doesn't exist
|
||||
local id_pe_acmeIdentifier = "1.3.6.1.5.5.7.1.31"
|
||||
local nid = objects.txt2nid(id_pe_acmeIdentifier)
|
||||
if not nid or nid == 0 then
|
||||
nid = objects.create(
|
||||
id_pe_acmeIdentifier, -- nid
|
||||
"pe-acmeIdentifier", -- sn
|
||||
"ACME Identifier" -- ln
|
||||
)
|
||||
end
|
||||
|
||||
-- generate the tls-alpn-01 challenge certificate/key per
|
||||
-- https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-07
|
||||
-- with given domain name and challenge token
|
||||
local function serve_challenge_cert(domain, challenge)
|
||||
local dgst = assert(digest.new("sha256"):final(challenge))
|
||||
|
||||
-- There're two ways to set ASN.1 octect string to the extension
|
||||
-- The recommanded way is to pass the string directly to extension.from_der()
|
||||
local _, err = extension.from_der(dgst, nid, true)
|
||||
if err then
|
||||
return nil, nil, err
|
||||
end
|
||||
-- OR we put the ASN.1 signature for this string by ourselves
|
||||
-- 0x04: OCTET STRING
|
||||
-- 0x20: length
|
||||
local dgst_hex = "DER:0420" .. dgst:gsub("(.)", function(s) return string.format("%02x", string.byte(s)) end)
|
||||
local ext, err = extension.new(nid, dgst_hex)
|
||||
if err then
|
||||
return nil, nil, err
|
||||
end
|
||||
ext:set_critical(true)
|
||||
|
||||
local key = pkey.new()
|
||||
local cert = x509.new()
|
||||
cert:set_pubkey(key)
|
||||
|
||||
cert:add_extension(ext)
|
||||
|
||||
local alt = assert(altname.new():add(
|
||||
"DNS", domain
|
||||
))
|
||||
local _, err = cert:set_subject_alt_name(alt)
|
||||
if err then
|
||||
return nil, nil, err
|
||||
end
|
||||
cert:sign(key)
|
||||
|
||||
return key, cert
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
local pkey = require("resty.openssl.pkey")
|
||||
|
||||
-- alice's private key
|
||||
local alice_priv = assert(pkey.new({
|
||||
type = "X25519"
|
||||
}))
|
||||
-- alice's public key, shared with bob
|
||||
local alice_pub = assert(pkey.new(alice_priv:to_PEM("public")))
|
||||
|
||||
-- bob's private key
|
||||
local bob_priv = assert(pkey.new({
|
||||
type = "X25519"
|
||||
}))
|
||||
-- bobs' public key, shared with alice
|
||||
local bob_pub = assert(pkey.new(bob_priv:to_PEM("public")))
|
||||
|
||||
ngx.say("alice and bob hold ",
|
||||
alice_priv:to_PEM() == bob_priv:to_PEM() and "same keys" or "different keys")
|
||||
|
||||
ngx.say("")
|
||||
|
||||
local k1 = assert(alice_priv:derive(bob_pub))
|
||||
ngx.say("alice use this key to talk with bob: ", ngx.encode_base64(k1))
|
||||
|
||||
local k2 = assert(bob_priv:derive(alice_pub))
|
||||
ngx.say("bob use this key to talk with alice: ", ngx.encode_base64(k2))
|
||||
|
||||
ngx.say("")
|
||||
|
||||
ngx.say(k1 == k2 and "key exchange is correct" or "key exchange is not correct")
|
||||
|
|
@ -0,0 +1,476 @@
|
|||
local ffi = require("ffi")
|
||||
local C = ffi.C
|
||||
local ffi_cast = ffi.cast
|
||||
local ffi_str = ffi.string
|
||||
|
||||
local format_error = require("resty.openssl.err").format_error
|
||||
|
||||
local OPENSSL_3X, BORINGSSL
|
||||
|
||||
local function try_require_modules()
|
||||
package.loaded["resty.openssl.version"] = nil
|
||||
|
||||
local pok, lib = pcall(require, "resty.openssl.version")
|
||||
if pok then
|
||||
OPENSSL_3X = lib.OPENSSL_3X
|
||||
BORINGSSL = lib.BORINGSSL
|
||||
|
||||
require "resty.openssl.include.crypto"
|
||||
require "resty.openssl.include.objects"
|
||||
else
|
||||
package.loaded["resty.openssl.version"] = nil
|
||||
end
|
||||
end
|
||||
try_require_modules()
|
||||
|
||||
|
||||
local _M = {
|
||||
_VERSION = '0.8.21',
|
||||
}
|
||||
|
||||
local libcrypto_name
|
||||
local lib_patterns = {
|
||||
"%s", "%s.so.3", "%s.so.1.1", "%s.so.1.0"
|
||||
}
|
||||
|
||||
function _M.load_library()
|
||||
for _, pattern in ipairs(lib_patterns) do
|
||||
-- true: load to global namespae
|
||||
local pok, _ = pcall(ffi.load, string.format(pattern, "crypto"), true)
|
||||
if pok then
|
||||
libcrypto_name = string.format(pattern, "crypto")
|
||||
ffi.load(string.format(pattern, "ssl"), true)
|
||||
|
||||
try_require_modules()
|
||||
|
||||
return libcrypto_name
|
||||
end
|
||||
end
|
||||
|
||||
return false, "unable to load crypto library"
|
||||
end
|
||||
|
||||
function _M.load_modules()
|
||||
_M.bn = require("resty.openssl.bn")
|
||||
_M.cipher = require("resty.openssl.cipher")
|
||||
_M.digest = require("resty.openssl.digest")
|
||||
_M.hmac = require("resty.openssl.hmac")
|
||||
_M.kdf = require("resty.openssl.kdf")
|
||||
_M.pkey = require("resty.openssl.pkey")
|
||||
_M.objects = require("resty.openssl.objects")
|
||||
_M.rand = require("resty.openssl.rand")
|
||||
_M.version = require("resty.openssl.version")
|
||||
_M.x509 = require("resty.openssl.x509")
|
||||
_M.altname = require("resty.openssl.x509.altname")
|
||||
_M.chain = require("resty.openssl.x509.chain")
|
||||
_M.csr = require("resty.openssl.x509.csr")
|
||||
_M.crl = require("resty.openssl.x509.crl")
|
||||
_M.extension = require("resty.openssl.x509.extension")
|
||||
_M.extensions = require("resty.openssl.x509.extensions")
|
||||
_M.name = require("resty.openssl.x509.name")
|
||||
_M.revoked = require("resty.openssl.x509.revoked")
|
||||
_M.store = require("resty.openssl.x509.store")
|
||||
_M.pkcs12 = require("resty.openssl.pkcs12")
|
||||
_M.ssl = require("resty.openssl.ssl")
|
||||
_M.ssl_ctx = require("resty.openssl.ssl_ctx")
|
||||
|
||||
if OPENSSL_3X then
|
||||
_M.provider = require("resty.openssl.provider")
|
||||
_M.mac = require("resty.openssl.mac")
|
||||
_M.ctx = require("resty.openssl.ctx")
|
||||
end
|
||||
|
||||
_M.bignum = _M.bn
|
||||
end
|
||||
|
||||
function _M.luaossl_compat()
|
||||
_M.load_modules()
|
||||
|
||||
_M.csr.setSubject = _M.csr.set_subject_name
|
||||
_M.csr.setPublicKey = _M.csr.set_pubkey
|
||||
|
||||
_M.x509.setPublicKey = _M.x509.set_pubkey
|
||||
_M.x509.getPublicKey = _M.x509.get_pubkey
|
||||
_M.x509.setSerial = _M.x509.set_serial_number
|
||||
_M.x509.getSerial = _M.x509.get_serial_number
|
||||
_M.x509.setSubject = _M.x509.set_subject_name
|
||||
_M.x509.getSubject = _M.x509.get_subject_name
|
||||
_M.x509.setIssuer = _M.x509.set_issuer_name
|
||||
_M.x509.getIssuer = _M.x509.get_issuer_name
|
||||
_M.x509.getOCSP = _M.x509.get_ocsp_url
|
||||
|
||||
local pkey_new = _M.pkey.new
|
||||
_M.pkey.new = function(a, b)
|
||||
if type(a) == "string" then
|
||||
return pkey_new(a, b and unpack(b))
|
||||
else
|
||||
return pkey_new(a, b)
|
||||
end
|
||||
end
|
||||
|
||||
_M.cipher.encrypt = function(self, key, iv, padding)
|
||||
return self, _M.cipher.init(self, key, iv, true, not padding)
|
||||
end
|
||||
_M.cipher.decrypt = function(self, key, iv, padding)
|
||||
return self, _M.cipher.init(self, key, iv, false, not padding)
|
||||
end
|
||||
|
||||
local digest_update = _M.digest.update
|
||||
_M.digest.update = function(self, ...)
|
||||
local ok, err = digest_update(self, ...)
|
||||
if ok then
|
||||
return self
|
||||
else
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
local store_verify = _M.store.verify
|
||||
_M.store.verify = function(...)
|
||||
local ok, err = store_verify(...)
|
||||
if err then
|
||||
return false, err
|
||||
else
|
||||
return true, ok
|
||||
end
|
||||
end
|
||||
|
||||
local kdf_derive = _M.kdf.derive
|
||||
local kdf_keys_mappings = {
|
||||
iter = "pbkdf2_iter",
|
||||
key = "hkdf_key",
|
||||
info = "hkdf_info",
|
||||
secret = "tls1_prf_secret",
|
||||
seed = "tls1_prf_seed",
|
||||
maxmem_bytes = "scrypt_maxmem",
|
||||
N = "scrypt_N",
|
||||
r = "scrypt_r",
|
||||
p = "scrypt_p",
|
||||
}
|
||||
_M.kdf.derive = function(o)
|
||||
for k1, k2 in pairs(kdf_keys_mappings) do
|
||||
o[k1] = o[k2]
|
||||
o[k2] = nil
|
||||
end
|
||||
local hkdf_mode = o.hkdf_mode
|
||||
if hkdf_mode == "extract_and_expand" then
|
||||
o.hkdf_mode = _M.kdf.HKDEF_MODE_EXTRACT_AND_EXPAND
|
||||
elseif hkdf_mode == "extract_only" then
|
||||
o.hkdf_mode = _M.kdf.HKDEF_MODE_EXTRACT_ONLY
|
||||
elseif hkdf_mode == "expand_only" then
|
||||
o.hkdf_mode = _M.kdf.HKDEF_MODE_EXPAND_ONLY
|
||||
end
|
||||
return kdf_derive(o)
|
||||
end
|
||||
|
||||
_M.pkcs12.new = function(tbl)
|
||||
local certs = {}
|
||||
local passphrase = tbl.passphrase
|
||||
if not tbl.key then
|
||||
return nil, "key must be set"
|
||||
end
|
||||
for _, cert in ipairs(tbl.certs) do
|
||||
if not _M.x509.istype(cert) then
|
||||
return nil, "certs must contains only x509 instance"
|
||||
end
|
||||
if cert:check_private_key(tbl.key) then
|
||||
tbl.cert = cert
|
||||
else
|
||||
certs[#certs+1] = cert
|
||||
end
|
||||
end
|
||||
tbl.cacerts = certs
|
||||
return _M.pkcs12.encode(tbl, passphrase)
|
||||
end
|
||||
|
||||
_M.crl.add = _M.crl.add_revoked
|
||||
_M.crl.lookupSerial = _M.crl.get_by_serial
|
||||
|
||||
for mod, tbl in pairs(_M) do
|
||||
if type(tbl) == 'table' then
|
||||
|
||||
-- avoid using a same table as the iterrator will change
|
||||
local new_tbl = {}
|
||||
-- luaossl always error() out
|
||||
for k, f in pairs(tbl) do
|
||||
if type(f) == 'function' then
|
||||
local of = f
|
||||
new_tbl[k] = function(...)
|
||||
local ret = { of(...) }
|
||||
if ret and #ret > 1 and ret[#ret] then
|
||||
error(mod .. "." .. k .. "(): " .. ret[#ret])
|
||||
end
|
||||
return unpack(ret)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for k, f in pairs(new_tbl) do
|
||||
tbl[k] = f
|
||||
end
|
||||
|
||||
setmetatable(tbl, {
|
||||
__index = function(t, k)
|
||||
local tok
|
||||
-- handle special case
|
||||
if k == 'toPEM' then
|
||||
tok = 'to_PEM'
|
||||
else
|
||||
tok = k:gsub("(%l)(%u)", function(a, b) return a .. "_" .. b:lower() end)
|
||||
if tok == k then
|
||||
return
|
||||
end
|
||||
end
|
||||
if type(tbl[tok]) == 'function' then
|
||||
return tbl[tok]
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
-- skip error() conversion
|
||||
_M.pkcs12.parse = function(p12, passphrase)
|
||||
local r, err = _M.pkcs12.decode(p12, passphrase)
|
||||
if err then error(err) end
|
||||
return r.key, r.cert, r.cacerts
|
||||
end
|
||||
end
|
||||
|
||||
if OPENSSL_3X then
|
||||
require "resty.openssl.include.evp"
|
||||
local provider = require "resty.openssl.provider"
|
||||
local ctx_lib = require "resty.openssl.ctx"
|
||||
local fips_provider_ctx
|
||||
|
||||
function _M.set_fips_mode(enable, self_test)
|
||||
if (not not enable) == _M.get_fips_mode() then
|
||||
return true
|
||||
end
|
||||
|
||||
if enable then
|
||||
local p, err = provider.load("fips")
|
||||
if not p then
|
||||
return false, err
|
||||
end
|
||||
fips_provider_ctx = p
|
||||
if self_test then
|
||||
local ok, err = p:self_test()
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
end
|
||||
|
||||
elseif fips_provider_ctx then -- disable
|
||||
local p = fips_provider_ctx
|
||||
fips_provider_ctx = nil
|
||||
return p:unload()
|
||||
end
|
||||
|
||||
-- set algorithm in fips mode in default ctx
|
||||
-- this deny/allow non-FIPS compliant algorithms to be used from EVP interface
|
||||
-- and redirect/remove redirect implementation to fips provider
|
||||
if C.EVP_default_properties_enable_fips(ctx_lib.get_libctx(), enable and 1 or 0) == 0 then
|
||||
return false, format_error("openssl.set_fips_mode: EVP_default_properties_enable_fips")
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function _M.get_fips_mode()
|
||||
local pok = provider.is_available("fips")
|
||||
if not pok then
|
||||
return false
|
||||
end
|
||||
|
||||
return C.EVP_default_properties_is_fips_enabled(ctx_lib.get_libctx()) == 1
|
||||
end
|
||||
|
||||
else
|
||||
function _M.set_fips_mode(enable)
|
||||
if (not not enable) == _M.get_fips_mode() then
|
||||
return true
|
||||
end
|
||||
|
||||
if C.FIPS_mode_set(enable and 1 or 0) == 0 then
|
||||
return false, format_error("openssl.set_fips_mode")
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function _M.get_fips_mode()
|
||||
return C.FIPS_mode() == 1
|
||||
end
|
||||
end
|
||||
|
||||
function _M.set_default_properties(props)
|
||||
if not OPENSSL_3X then
|
||||
return nil, "openssl.set_default_properties is only not supported from OpenSSL 3.0"
|
||||
end
|
||||
|
||||
local ctx_lib = require "resty.openssl.ctx"
|
||||
|
||||
if C.EVP_set_default_properties(ctx_lib.get_libctx(), props) == 0 then
|
||||
return false, format_error("openssl.EVP_set_default_properties")
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function list_legacy(typ, get_nid_cf)
|
||||
local typ_lower = string.lower(typ:sub(5)) -- cut off EVP_
|
||||
require ("resty.openssl.include.evp." .. typ_lower)
|
||||
|
||||
local ret = {}
|
||||
local fn = ffi_cast("fake_openssl_" .. typ_lower .. "_list_fn*",
|
||||
function(elem, from, to, arg)
|
||||
if elem ~= nil then
|
||||
local nid = get_nid_cf(elem)
|
||||
table.insert(ret, ffi_str(C.OBJ_nid2sn(nid)))
|
||||
end
|
||||
-- from/to (renamings) are ignored
|
||||
end)
|
||||
C[typ .. "_do_all_sorted"](fn, nil)
|
||||
fn:free()
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
local function list_provided(typ)
|
||||
local typ_lower = string.lower(typ:sub(5)) -- cut off EVP_
|
||||
local typ_ptr = typ .. "*"
|
||||
require ("resty.openssl.include.evp." .. typ_lower)
|
||||
local ctx_lib = require "resty.openssl.ctx"
|
||||
|
||||
local ret = {}
|
||||
|
||||
local fn = ffi_cast("fake_openssl_" .. typ_lower .. "_provided_list_fn*",
|
||||
function(elem, _)
|
||||
elem = ffi_cast(typ_ptr, elem)
|
||||
local name = ffi_str(C[typ .. "_get0_name"](elem))
|
||||
-- alternate names are ignored, retrieve use TYPE_names_do_all
|
||||
local prov = ffi_str(C.OSSL_PROVIDER_get0_name(C[typ .. "_get0_provider"](elem)))
|
||||
table.insert(ret, name .. " @ " .. prov)
|
||||
end)
|
||||
|
||||
C[typ .. "_do_all_provided"](ctx_lib.get_libctx(), fn, nil)
|
||||
fn:free()
|
||||
|
||||
table.sort(ret)
|
||||
return ret
|
||||
end
|
||||
|
||||
function _M.list_cipher_algorithms()
|
||||
if BORINGSSL then
|
||||
return nil, "openssl.list_cipher_algorithms is not supported on BoringSSL"
|
||||
end
|
||||
|
||||
require "resty.openssl.include.evp.cipher"
|
||||
local ret = list_legacy("EVP_CIPHER",
|
||||
OPENSSL_3X and C.EVP_CIPHER_get_nid or C.EVP_CIPHER_nid)
|
||||
|
||||
if OPENSSL_3X then
|
||||
local ret_provided = list_provided("EVP_CIPHER")
|
||||
for _, r in ipairs(ret_provided) do
|
||||
table.insert(ret, r)
|
||||
end
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
function _M.list_digest_algorithms()
|
||||
if BORINGSSL then
|
||||
return nil, "openssl.list_digest_algorithms is not supported on BoringSSL"
|
||||
end
|
||||
|
||||
require "resty.openssl.include.evp.md"
|
||||
local ret = list_legacy("EVP_MD",
|
||||
OPENSSL_3X and C.EVP_MD_get_type or C.EVP_MD_type)
|
||||
|
||||
if OPENSSL_3X then
|
||||
local ret_provided = list_provided("EVP_MD")
|
||||
for _, r in ipairs(ret_provided) do
|
||||
table.insert(ret, r)
|
||||
end
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
function _M.list_mac_algorithms()
|
||||
if not OPENSSL_3X then
|
||||
return nil, "openssl.list_mac_algorithms is only supported from OpenSSL 3.0"
|
||||
end
|
||||
|
||||
return list_provided("EVP_MAC")
|
||||
end
|
||||
|
||||
function _M.list_kdf_algorithms()
|
||||
if not OPENSSL_3X then
|
||||
return nil, "openssl.list_kdf_algorithms is only supported from OpenSSL 3.0"
|
||||
end
|
||||
|
||||
return list_provided("EVP_KDF")
|
||||
end
|
||||
|
||||
local valid_ssl_protocols = {
|
||||
["SSLv3"] = 0x0300,
|
||||
["TLSv1"] = 0x0301,
|
||||
["TLSv1.1"] = 0x0302,
|
||||
["TLSv1.2"] = 0x0303,
|
||||
["TLSv1.3"] = 0x0304,
|
||||
}
|
||||
|
||||
function _M.list_ssl_ciphers(cipher_list, ciphersuites, protocol)
|
||||
local ssl_lib = require("resty.openssl.ssl")
|
||||
local ssl_macro = require("resty.openssl.include.ssl")
|
||||
|
||||
if protocol then
|
||||
if not valid_ssl_protocols[protocol] then
|
||||
return nil, "unknown protocol \"" .. protocol .. "\""
|
||||
end
|
||||
protocol = valid_ssl_protocols[protocol]
|
||||
end
|
||||
|
||||
local ssl_ctx = C.SSL_CTX_new(C.TLS_server_method())
|
||||
if ssl_ctx == nil then
|
||||
return nil, format_error("SSL_CTX_new")
|
||||
end
|
||||
ffi.gc(ssl_ctx, C.SSL_CTX_free)
|
||||
|
||||
local ssl = C.SSL_new(ssl_ctx)
|
||||
if ssl == nil then
|
||||
return nil, format_error("SSL_new")
|
||||
end
|
||||
ffi.gc(ssl, C.SSL_free)
|
||||
|
||||
if protocol then
|
||||
if ssl_macro.SSL_set_min_proto_version(ssl, protocol) == 0 or
|
||||
ssl_macro.SSL_set_max_proto_version(ssl, protocol) == 0 then
|
||||
return nil, format_error("SSL_set_min/max_proto_version")
|
||||
end
|
||||
end
|
||||
|
||||
ssl = { ctx = ssl }
|
||||
|
||||
local ok, err
|
||||
if cipher_list then
|
||||
ok, err = ssl_lib.set_cipher_list(ssl, cipher_list)
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
if ciphersuites then
|
||||
ok, err = ssl_lib.set_ciphersuites(ssl, ciphersuites)
|
||||
if not ok then
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
return ssl_lib.get_ciphers(ssl)
|
||||
end
|
||||
|
||||
return _M
|
|
@ -0,0 +1,91 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
local ffi_str = ffi.string
|
||||
local floor = math.floor
|
||||
|
||||
local asn1_macro = require("resty.openssl.include.asn1")
|
||||
|
||||
-- https://github.com/wahern/luaossl/blob/master/src/openssl.c
|
||||
local function isleap(year)
|
||||
return (year % 4) == 0 and ((year % 100) > 0 or (year % 400) == 0)
|
||||
end
|
||||
|
||||
local past = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }
|
||||
local function yday(year, mon, mday)
|
||||
local d = past[mon] + mday - 1
|
||||
if mon > 2 and isleap(year) then
|
||||
d = d + 1
|
||||
end
|
||||
return d
|
||||
end
|
||||
|
||||
local function leaps(year)
|
||||
return floor(year / 400) + floor(year / 4) - floor(year / 100)
|
||||
end
|
||||
|
||||
local function asn1_to_unix(asn1)
|
||||
if asn1 == nil then
|
||||
return nil, "except an ASN1 instance at #1, got nil"
|
||||
end
|
||||
|
||||
local s = asn1_macro.ASN1_STRING_get0_data(asn1)
|
||||
s = ffi_str(s)
|
||||
-- V_ASN1_UTCTIME 190303223958Z
|
||||
-- V_ASN1_GENERALIZEDTIME 21190822162753Z
|
||||
local yyoffset = 2
|
||||
local year
|
||||
-- # define V_ASN1_GENERALIZEDTIME 24
|
||||
if C.ASN1_STRING_type(asn1) == 24 then
|
||||
yyoffset = 4
|
||||
year = tonumber(s:sub(1, yyoffset))
|
||||
else
|
||||
year = tonumber(s:sub(1, yyoffset))
|
||||
year = year + (year < 50 and 2000 or 1900)
|
||||
end
|
||||
local month = tonumber(s:sub(yyoffset+1, yyoffset+2))
|
||||
if month > 12 or month < 1 then
|
||||
return nil, "asn1.asn1_to_unix: bad format " .. s
|
||||
end
|
||||
local day = tonumber(s:sub(yyoffset+3, yyoffset+4))
|
||||
if day > 31 or day < 1 then
|
||||
return nil, "asn1.asn1_to_unix: bad format " .. s
|
||||
end
|
||||
local hour = tonumber(s:sub(yyoffset+5, yyoffset+6))
|
||||
if hour > 23 or hour < 0 then
|
||||
return nil, "asn1.asn1_to_unix: bad format " .. s
|
||||
end
|
||||
local minute = tonumber(s:sub(yyoffset+7, yyoffset+8))
|
||||
if minute > 59 or hour < 0 then
|
||||
return nil, "asn1.asn1_to_unix: bad format " .. s
|
||||
end
|
||||
local second = tonumber(s:sub(yyoffset+9, yyoffset+10))
|
||||
if second > 59 or second < 0 then
|
||||
return nil, "asn1.asn1_to_unix: bad format " .. s
|
||||
end
|
||||
|
||||
local tm
|
||||
tm = (year - 1970) * 365
|
||||
tm = tm + leaps(year - 1) - leaps(1969)
|
||||
tm = (tm + yday(year, month, day)) * 24
|
||||
tm = (tm + hour) * 60
|
||||
tm = (tm + minute) * 60
|
||||
tm = tm + second
|
||||
|
||||
-- offset?
|
||||
local sign = s:sub(yyoffset+11, yyoffset+11)
|
||||
if sign == "+" or sign == "-" then
|
||||
local sgn = sign == "+" and 1 or -1
|
||||
local hh = tonumber(s:sub(yyoffset+12, yyoffset+13) or 'no')
|
||||
local mm = tonumber(s:sub(yyoffset+14, yyoffset+15) or 'no')
|
||||
if not hh or not mm then
|
||||
return nil, "asn1.asn1_to_unix: bad format " .. s
|
||||
end
|
||||
tm = tm + sgn * (hh * 3600 + mm * 60)
|
||||
end
|
||||
|
||||
return tm
|
||||
end
|
||||
|
||||
return {
|
||||
asn1_to_unix = asn1_to_unix,
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
local ffi_gc = ffi.gc
|
||||
local ffi_new = ffi.new
|
||||
local ffi_str = ffi.string
|
||||
|
||||
require "resty.openssl.include.bio"
|
||||
local format_error = require("resty.openssl.err").format_error
|
||||
|
||||
local function read_wrap(f, ...)
|
||||
if type(f) ~= "cdata" then -- should be explictly a function
|
||||
return nil, "bio_util.read_wrap: expect a function at #1"
|
||||
end
|
||||
|
||||
local bio_method = C.BIO_s_mem()
|
||||
if bio_method == nil then
|
||||
return nil, "bio_util.read_wrap: BIO_s_mem() failed"
|
||||
end
|
||||
local bio = C.BIO_new(bio_method)
|
||||
ffi_gc(bio, C.BIO_free)
|
||||
|
||||
-- BIO_reset; #define BIO_CTRL_RESET 1
|
||||
local code = C.BIO_ctrl(bio, 1, 0, nil)
|
||||
if code ~= 1 then
|
||||
return nil, "bio_util.read_wrap: BIO_ctrl() failed: " .. code
|
||||
end
|
||||
|
||||
local code = f(bio, ...)
|
||||
if code ~= 1 then
|
||||
return nil, format_error(f, code)
|
||||
end
|
||||
|
||||
local buf = ffi_new("char *[1]")
|
||||
|
||||
-- BIO_get_mem_data; #define BIO_CTRL_INFO 3
|
||||
local length = C.BIO_ctrl(bio, 3, 0, buf)
|
||||
|
||||
return ffi_str(buf[0], length)
|
||||
end
|
||||
|
||||
return {
|
||||
read_wrap = read_wrap,
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
-- Put common type definition at the same place for convenience
|
||||
-- and standarlization
|
||||
local ffi = require "ffi"
|
||||
|
||||
--[[
|
||||
TYPE_ptr: usually used to define a pointer (to cast or something)
|
||||
char* var_name; // <- we use char_ptr
|
||||
|
||||
ptr_of_TYPE: usually used to pass the pointer of an object that
|
||||
is already allocated. so that we can also set value of it as well
|
||||
|
||||
int p = 2; // ptr_of_int(); ptr_of_int[0] = 2;
|
||||
plus_one(&p); // <- we use ptr_of_int
|
||||
]]
|
||||
|
||||
return {
|
||||
void_ptr = ffi.typeof("void *"),
|
||||
ptr_of_uint64 = ffi.typeof("uint64_t[1]"),
|
||||
ptr_of_uint = ffi.typeof("unsigned int[1]"),
|
||||
ptr_of_size_t = ffi.typeof("size_t[1]"),
|
||||
ptr_of_int = ffi.typeof("int[1]"),
|
||||
null = ffi.new("void *"), -- hack wher ngx.null is not available
|
||||
|
||||
uchar_array = ffi.typeof("unsigned char[?]"),
|
||||
uchar_ptr = ffi.typeof("unsigned char*"),
|
||||
|
||||
SIZE_MAX = math.pow(2, 64), -- nginx set _FILE_OFFSET_BITS to 64
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
local ffi = require "ffi"
|
||||
local ffi_new = ffi.new
|
||||
local ffi_gc = ffi.gc
|
||||
local ffi_str = ffi.string
|
||||
local C = ffi.C
|
||||
|
||||
require "resty.openssl.include.ecdsa"
|
||||
local bn_lib = require "resty.openssl.bn"
|
||||
local format_error = require("resty.openssl.err").format_error
|
||||
local ceil = math.ceil
|
||||
|
||||
local _M = {}
|
||||
|
||||
--[[ A DER formatted ECDSA signature looks like
|
||||
SEQUENCE {
|
||||
INTEGER
|
||||
4B 5F CF E8 A7 BD 6A C2 1D 25 0D F8 DE 9C EF DC
|
||||
C4 DF 33 F3 AF 2F 3D 5B 83 2C 1F BD 98 C8 61 34
|
||||
INTEGER
|
||||
7E F9 E9 60 B1 E6 7F 59 9E 2C 38 22 39 B2 C4 B1
|
||||
71 3E FA AE 24 A4 B7 D2 03 5A 60 8D F3 34 3D E8
|
||||
}
|
||||
|
||||
It has ASN.1 headers on both the SEQUENCE and INTEGERs, so
|
||||
the total length is typically 70 bytes (3 headers, 2 bytes each).
|
||||
The binary form is typically 64 bytes.
|
||||
]]
|
||||
|
||||
local function group_size(ec_key)
|
||||
local group = C.EC_KEY_get0_group(ec_key)
|
||||
if group == nil then
|
||||
assert("failed to get EC group", 2)
|
||||
end
|
||||
|
||||
local sz = C.EC_GROUP_order_bits(group)
|
||||
if sz <= 0 then
|
||||
assert("failed to get EC group order bits", 2)
|
||||
end
|
||||
|
||||
return ceil(sz / 8)
|
||||
end
|
||||
|
||||
_M.sig_der2raw = function(der, ec_key)
|
||||
if ec_key == nil then
|
||||
error("ec_key is required", 2)
|
||||
end
|
||||
local psize = group_size(ec_key)
|
||||
|
||||
local buf = ffi.new("const unsigned char*", der)
|
||||
local buf_ptr = ffi.new("const unsigned char*[1]", buf)
|
||||
local sig = C.d2i_ECDSA_SIG(nil, buf_ptr, #der)
|
||||
if sig == nil then
|
||||
return nil, format_error("failed to parse ECDSA signature: d2i_ECDSA_SIG")
|
||||
end
|
||||
|
||||
ffi_gc(sig, C.ECDSA_SIG_free)
|
||||
|
||||
local bn_r_ptr = ffi_new("const BIGNUM*[1]")
|
||||
local bn_s_ptr = ffi_new("const BIGNUM*[1]")
|
||||
|
||||
C.ECDSA_SIG_get0(sig, bn_r_ptr, bn_s_ptr)
|
||||
|
||||
if bn_r_ptr[0] == nil or bn_s_ptr[0] == nil then
|
||||
return nil, format_error("failed to get r or s from sig")
|
||||
end
|
||||
|
||||
local bn_r = bn_lib.dup(bn_r_ptr[0])
|
||||
local bn_s = bn_lib.dup(bn_s_ptr[0])
|
||||
|
||||
if bn_r == nil or bn_s == nil then
|
||||
return nil, format_error("failed to dup r or s")
|
||||
end
|
||||
|
||||
local rbin, err = bn_r:to_binary(psize)
|
||||
if err then
|
||||
return nil, "failed to parse r to binary: " .. err
|
||||
end
|
||||
local sbin, err = bn_s:to_binary(psize)
|
||||
if err then
|
||||
return nil, "failed to parse s to binary: " .. err
|
||||
end
|
||||
|
||||
return rbin .. sbin
|
||||
end
|
||||
|
||||
_M.sig_raw2der = function(bin, ec_key)
|
||||
if ec_key == nil then
|
||||
error("ec_key is required", 2)
|
||||
end
|
||||
|
||||
local psize = group_size(ec_key)
|
||||
|
||||
if #bin ~= psize * 2 then
|
||||
return nil, "invalid signature length, expect " .. (psize * 2) .. " but got " .. #bin
|
||||
end
|
||||
|
||||
local rbin = string.sub(bin, 1, psize)
|
||||
local sbin = string.sub(bin, psize + 1)
|
||||
|
||||
local bn_r, err = bn_lib.from_binary(rbin)
|
||||
if err then
|
||||
return nil, "failed to parse r from binary: " .. err
|
||||
end
|
||||
local bn_s, err = bn_lib.from_binary(sbin)
|
||||
if err then
|
||||
return nil, "failed to parse s from binary: " .. err
|
||||
end
|
||||
|
||||
local sig = C.ECDSA_SIG_new()
|
||||
if sig == nil then
|
||||
return nil, format_error("ECDSA_SIG_new")
|
||||
end
|
||||
|
||||
ffi_gc(sig, C.ECDSA_SIG_free)
|
||||
|
||||
local bn_r0 = C.BN_dup(bn_r.ctx)
|
||||
local bn_s0 = C.BN_dup(bn_s.ctx)
|
||||
if not bn_r0 or not bn_s0 then
|
||||
return nil, format_error("failed to BN_dup r or s")
|
||||
end
|
||||
|
||||
local ok = C.ECDSA_SIG_set0(sig, bn_r0, bn_s0)
|
||||
if ok ~= 1 then
|
||||
return nil, format_error("failed to set r and s to sig")
|
||||
end
|
||||
|
||||
local der_len = C.i2d_ECDSA_SIG(sig, nil)
|
||||
if der_len <= 0 then
|
||||
return nil, format_error("failed to get ECDSA signature size")
|
||||
end
|
||||
|
||||
local buf = ffi_new("unsigned char[?]", der_len)
|
||||
local buf_ptr = ffi.new("unsigned char*[1]", buf)
|
||||
|
||||
der_len = C.i2d_ECDSA_SIG(sig, buf_ptr)
|
||||
if der_len <= 0 then
|
||||
return nil, format_error("failed to encode ECDSA signature to DER")
|
||||
end
|
||||
|
||||
return ffi_str(buf, der_len)
|
||||
end
|
||||
|
||||
return _M
|
|
@ -0,0 +1,261 @@
|
|||
|
||||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
|
||||
local cjson = require("cjson.safe")
|
||||
local b64 = require("ngx.base64")
|
||||
|
||||
local evp_macro = require "resty.openssl.include.evp"
|
||||
local rsa_lib = require "resty.openssl.rsa"
|
||||
local ec_lib = require "resty.openssl.ec"
|
||||
local ecx_lib = require "resty.openssl.ecx"
|
||||
local bn_lib = require "resty.openssl.bn"
|
||||
local digest_lib = require "resty.openssl.digest"
|
||||
|
||||
local _M = {}
|
||||
|
||||
local rsa_jwk_params = {"n", "e", "d", "p", "q", "dp", "dq", "qi"}
|
||||
local rsa_openssl_params = rsa_lib.params
|
||||
|
||||
local function load_jwk_rsa(tbl)
|
||||
if not tbl["n"] or not tbl["e"] then
|
||||
return nil, "at least \"n\" and \"e\" parameter is required"
|
||||
end
|
||||
|
||||
local params = {}
|
||||
local err
|
||||
for i, k in ipairs(rsa_jwk_params) do
|
||||
local v = tbl[k]
|
||||
if v then
|
||||
v = b64.decode_base64url(v)
|
||||
if not v then
|
||||
return nil, "cannot decode parameter \"" .. k .. "\" from base64 " .. tbl[k]
|
||||
end
|
||||
|
||||
params[rsa_openssl_params[i]], err = bn_lib.from_binary(v)
|
||||
if err then
|
||||
return nil, "cannot use parameter \"" .. k .. "\": " .. err
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local key = C.RSA_new()
|
||||
if key == nil then
|
||||
return nil, "RSA_new() failed"
|
||||
end
|
||||
|
||||
local _, err = rsa_lib.set_parameters(key, params)
|
||||
if err ~= nil then
|
||||
C.RSA_free(key)
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return key
|
||||
end
|
||||
|
||||
local ec_curves = {
|
||||
["P-256"] = C.OBJ_ln2nid("prime256v1"),
|
||||
["P-384"] = C.OBJ_ln2nid("secp384r1"),
|
||||
["P-521"] = C.OBJ_ln2nid("secp521r1"),
|
||||
}
|
||||
|
||||
local ec_curves_reverse = {}
|
||||
for k, v in pairs(ec_curves) do
|
||||
ec_curves_reverse[v] = k
|
||||
end
|
||||
|
||||
local ec_jwk_params = {"x", "y", "d"}
|
||||
|
||||
local function load_jwk_ec(tbl)
|
||||
local curve = tbl['crv']
|
||||
if not curve then
|
||||
return nil, "\"crv\" not defined for EC key"
|
||||
end
|
||||
if not tbl["x"] or not tbl["y"] then
|
||||
return nil, "at least \"x\" and \"y\" parameter is required"
|
||||
end
|
||||
local curve_nid = ec_curves[curve]
|
||||
if not curve_nid then
|
||||
return nil, "curve \"" .. curve .. "\" is not supported by this library"
|
||||
elseif curve_nid == 0 then
|
||||
return nil, "curve \"" .. curve .. "\" is not supported by linked OpenSSL"
|
||||
end
|
||||
|
||||
local params = {}
|
||||
local err
|
||||
for _, k in ipairs(ec_jwk_params) do
|
||||
local v = tbl[k]
|
||||
if v then
|
||||
v = b64.decode_base64url(v)
|
||||
if not v then
|
||||
return nil, "cannot decode parameter \"" .. k .. "\" from base64 " .. tbl[k]
|
||||
end
|
||||
|
||||
params[k], err = bn_lib.from_binary(v)
|
||||
if err then
|
||||
return nil, "cannot use parameter \"" .. k .. "\": " .. err
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- map to the name we expect
|
||||
if params["d"] then
|
||||
params["private"] = params["d"]
|
||||
params["d"] = nil
|
||||
end
|
||||
params["group"] = curve_nid
|
||||
|
||||
local key = C.EC_KEY_new()
|
||||
if key == nil then
|
||||
return nil, "EC_KEY_new() failed"
|
||||
end
|
||||
|
||||
local _, err = ec_lib.set_parameters(key, params)
|
||||
if err ~= nil then
|
||||
C.EC_KEY_free(key)
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return key
|
||||
end
|
||||
|
||||
local function load_jwk_okp(key_type, tbl)
|
||||
local params = {}
|
||||
if tbl["d"] then
|
||||
params.private = b64.decode_base64url(tbl["d"])
|
||||
elseif tbl["x"] then
|
||||
params.public = b64.decode_base64url(tbl["x"])
|
||||
else
|
||||
return nil, "at least \"x\" or \"d\" parameter is required"
|
||||
end
|
||||
local key, err = ecx_lib.set_parameters(key_type, nil, params)
|
||||
if err ~= nil then
|
||||
return nil, err
|
||||
end
|
||||
return key
|
||||
end
|
||||
|
||||
local ecx_curves_reverse = {}
|
||||
for k, v in pairs(evp_macro.ecx_curves) do
|
||||
ecx_curves_reverse[v] = k
|
||||
end
|
||||
|
||||
function _M.load_jwk(txt)
|
||||
local tbl, err = cjson.decode(txt)
|
||||
if err then
|
||||
return nil, "error decoding JSON from JWK: " .. err
|
||||
elseif type(tbl) ~= "table" then
|
||||
return nil, "except input to be decoded as a table, got " .. type(tbl)
|
||||
end
|
||||
|
||||
local key, key_free, key_type, err
|
||||
|
||||
if tbl["kty"] == "RSA" then
|
||||
key_type = evp_macro.EVP_PKEY_RSA
|
||||
if key_type == 0 then
|
||||
return nil, "the linked OpenSSL library doesn't support RSA key"
|
||||
end
|
||||
key, err = load_jwk_rsa(tbl)
|
||||
key_free = C.RSA_free
|
||||
elseif tbl["kty"] == "EC" then
|
||||
key_type = evp_macro.EVP_PKEY_EC
|
||||
if key_type == 0 then
|
||||
return nil, "the linked OpenSSL library doesn't support EC key"
|
||||
end
|
||||
key, err = load_jwk_ec(tbl)
|
||||
key_free = C.EC_KEY_free
|
||||
elseif tbl["kty"] == "OKP" then
|
||||
local curve = tbl["crv"]
|
||||
key_type = evp_macro.ecx_curves[curve]
|
||||
if not key_type then
|
||||
return nil, "unknown curve \"" .. tostring(curve)
|
||||
elseif key_type == 0 then
|
||||
return nil, "the linked OpenSSL library doesn't support \"" .. curve .. "\" key"
|
||||
end
|
||||
key, err = load_jwk_okp(key_type, tbl)
|
||||
if key ~= nil then
|
||||
return key
|
||||
end
|
||||
else
|
||||
return nil, "not yet supported jwk type \"" .. (tbl["kty"] or "nil") .. "\""
|
||||
end
|
||||
|
||||
if err then
|
||||
return nil, "failed to construct " .. tbl["kty"] .. " key from JWK: " .. err
|
||||
end
|
||||
|
||||
local ctx = C.EVP_PKEY_new()
|
||||
if ctx == nil then
|
||||
key_free(key)
|
||||
return nil, "EVP_PKEY_new() failed"
|
||||
end
|
||||
|
||||
local code = C.EVP_PKEY_assign(ctx, key_type, key)
|
||||
if code ~= 1 then
|
||||
key_free(key)
|
||||
C.EVP_PKEY_free(ctx)
|
||||
return nil, "EVP_PKEY_assign() failed"
|
||||
end
|
||||
|
||||
return ctx
|
||||
end
|
||||
|
||||
function _M.dump_jwk(pkey, is_priv)
|
||||
local jwk
|
||||
if pkey.key_type == evp_macro.EVP_PKEY_RSA then
|
||||
local param_keys = { "n" , "e" }
|
||||
if is_priv then
|
||||
param_keys = rsa_jwk_params
|
||||
end
|
||||
local params, err = pkey:get_parameters()
|
||||
if err then
|
||||
return nil, "jwk.dump_jwk: " .. err
|
||||
end
|
||||
jwk = {
|
||||
kty = "RSA",
|
||||
}
|
||||
for i, p in ipairs(param_keys) do
|
||||
local v = params[rsa_openssl_params[i]]:to_binary()
|
||||
jwk[p] = b64.encode_base64url(v)
|
||||
end
|
||||
elseif pkey.key_type == evp_macro.EVP_PKEY_EC then
|
||||
local params, err = pkey:get_parameters()
|
||||
if err then
|
||||
return nil, "jwk.dump_jwk: " .. err
|
||||
end
|
||||
jwk = {
|
||||
kty = "EC",
|
||||
crv = ec_curves_reverse[params.group],
|
||||
x = b64.encode_base64url(params.x:to_binary()),
|
||||
y = b64.encode_base64url(params.x:to_binary()),
|
||||
}
|
||||
if is_priv then
|
||||
jwk.d = b64.encode_base64url(params.private:to_binary())
|
||||
end
|
||||
elseif ecx_curves_reverse[pkey.key_type] then
|
||||
local params, err = pkey:get_parameters()
|
||||
if err then
|
||||
return nil, "jwk.dump_jwk: " .. err
|
||||
end
|
||||
jwk = {
|
||||
kty = "OKP",
|
||||
crv = ecx_curves_reverse[pkey.key_type],
|
||||
d = b64.encode_base64url(params.private),
|
||||
x = b64.encode_base64url(params.public),
|
||||
}
|
||||
else
|
||||
return nil, "jwk.dump_jwk: not implemented for this key type"
|
||||
end
|
||||
|
||||
local der = pkey:tostring(is_priv and "private" or "public", "DER")
|
||||
local dgst = digest_lib.new("sha256")
|
||||
local d, err = dgst:final(der)
|
||||
if err then
|
||||
return nil, "jwk.dump_jwk: failed to calculate digest for key"
|
||||
end
|
||||
jwk.kid = b64.encode_base64url(d)
|
||||
|
||||
return cjson.encode(jwk)
|
||||
end
|
||||
|
||||
return _M
|
|
@ -0,0 +1,318 @@
|
|||
local get_req_ssl, get_req_ssl_ctx
|
||||
local get_socket_ssl, get_socket_ssl_ctx
|
||||
|
||||
local pok, nginx_c = pcall(require, "resty.openssl.auxiliary.nginx_c")
|
||||
|
||||
if pok and not os.getenv("CI_SKIP_NGINX_C") then
|
||||
get_req_ssl = nginx_c.get_req_ssl
|
||||
get_req_ssl_ctx = nginx_c.get_req_ssl_ctx
|
||||
get_socket_ssl = nginx_c.get_socket_ssl
|
||||
get_socket_ssl_ctx = nginx_c.get_socket_ssl
|
||||
else
|
||||
local ffi = require "ffi"
|
||||
|
||||
ffi.cdef [[
|
||||
// Nginx seems to always config _FILE_OFFSET_BITS=64, this should always be 8 byte
|
||||
typedef long long off_t;
|
||||
typedef unsigned int socklen_t; // windows uses int, same size
|
||||
typedef unsigned short in_port_t;
|
||||
|
||||
typedef struct ssl_st SSL;
|
||||
typedef struct ssl_ctx_st SSL_CTX;
|
||||
|
||||
typedef long (*ngx_recv_pt)(void *c, void *buf, size_t size);
|
||||
typedef long (*ngx_recv_chain_pt)(void *c, void *in,
|
||||
off_t limit);
|
||||
typedef long (*ngx_send_pt)(void *c, void *buf, size_t size);
|
||||
typedef void *(*ngx_send_chain_pt)(void *c, void *in,
|
||||
off_t limit);
|
||||
|
||||
typedef struct {
|
||||
size_t len;
|
||||
void *data;
|
||||
} ngx_str_t;
|
||||
|
||||
typedef struct {
|
||||
SSL *connection;
|
||||
SSL_CTX *session_ctx;
|
||||
// trimmed
|
||||
} ngx_ssl_connection_s;
|
||||
]]
|
||||
|
||||
local ngx_version = ngx.config.nginx_version
|
||||
if ngx_version == 1017008 or ngx_version == 1019003 or ngx_version == 1019009
|
||||
or ngx_version == 1021004 then
|
||||
-- 1.17.8, 1.19.3, 1.19.9, 1.21.4
|
||||
-- https://github.com/nginx/nginx/blob/master/src/core/ngx_connection.h
|
||||
ffi.cdef [[
|
||||
typedef struct {
|
||||
ngx_str_t src_addr;
|
||||
ngx_str_t dst_addr;
|
||||
in_port_t src_port;
|
||||
in_port_t dst_port;
|
||||
} ngx_proxy_protocol_t;
|
||||
|
||||
typedef struct {
|
||||
void *data;
|
||||
void *read;
|
||||
void *write;
|
||||
|
||||
int fd;
|
||||
|
||||
ngx_recv_pt recv;
|
||||
ngx_send_pt send;
|
||||
ngx_recv_chain_pt recv_chain;
|
||||
ngx_send_chain_pt send_chain;
|
||||
|
||||
void *listening;
|
||||
|
||||
off_t sent;
|
||||
|
||||
void *log;
|
||||
|
||||
void *pool;
|
||||
|
||||
int type;
|
||||
|
||||
void *sockaddr;
|
||||
socklen_t socklen;
|
||||
ngx_str_t addr_text;
|
||||
|
||||
// https://github.com/nginx/nginx/commit/be932e81a1531a3ba032febad968fc2006c4fa48
|
||||
ngx_proxy_protocol_t *proxy_protocol;
|
||||
|
||||
ngx_ssl_connection_s *ssl;
|
||||
// trimmed
|
||||
} ngx_connection_s;
|
||||
]]
|
||||
else
|
||||
error("resty.openssl.auxiliary.nginx doesn't support Nginx version " .. ngx_version, 2)
|
||||
end
|
||||
|
||||
ffi.cdef [[
|
||||
typedef struct {
|
||||
ngx_connection_s *connection;
|
||||
// trimmed
|
||||
} ngx_stream_lua_request_s;
|
||||
|
||||
typedef struct {
|
||||
unsigned int signature; /* "HTTP" */
|
||||
|
||||
ngx_connection_s *connection;
|
||||
// trimmed
|
||||
} ngx_http_request_s;
|
||||
]]
|
||||
|
||||
local get_request
|
||||
do
|
||||
local ok, exdata = pcall(require, "thread.exdata")
|
||||
if ok and exdata then
|
||||
function get_request()
|
||||
local r = exdata()
|
||||
if r ~= nil then
|
||||
return r
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
local getfenv = getfenv
|
||||
|
||||
function get_request()
|
||||
return getfenv(0).__ngx_req
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local SOCKET_CTX_INDEX = 1
|
||||
|
||||
local NO_C_MODULE_WARNING_MSG_SHOWN = false
|
||||
local NO_C_MODULE_WARNING_MSG = "note resty.openssl.auxiliary.nginx is using plain FFI " ..
|
||||
"and it's only intended to be used in development, " ..
|
||||
"consider using lua-resty-openssl.aux-module in production."
|
||||
|
||||
local function get_ngx_ssl_from_req()
|
||||
if not NO_C_MODULE_WARNING_MSG_SHOWN then
|
||||
ngx.log(ngx.WARN, NO_C_MODULE_WARNING_MSG)
|
||||
NO_C_MODULE_WARNING_MSG_SHOWN = true
|
||||
end
|
||||
|
||||
local c = get_request()
|
||||
if ngx.config.subsystem == "stream" then
|
||||
c = ffi.cast("ngx_stream_lua_request_s*", c)
|
||||
else -- http
|
||||
c = ffi.cast("ngx_http_request_s*", c)
|
||||
end
|
||||
|
||||
local ngx_ssl = c.connection.ssl
|
||||
if ngx_ssl == nil then
|
||||
return nil, "c.connection.ssl is nil"
|
||||
end
|
||||
return ngx_ssl
|
||||
end
|
||||
|
||||
get_req_ssl = function()
|
||||
local ssl, err = get_ngx_ssl_from_req()
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return ssl.connection
|
||||
end
|
||||
|
||||
get_req_ssl_ctx = function()
|
||||
local ssl, err = get_ngx_ssl_from_req()
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return ssl.session_ctx
|
||||
end
|
||||
|
||||
ffi.cdef[[
|
||||
typedef struct ngx_http_lua_socket_tcp_upstream_s
|
||||
ngx_http_lua_socket_tcp_upstream_t;
|
||||
|
||||
typedef struct {
|
||||
ngx_connection_s *connection;
|
||||
// trimmed
|
||||
} ngx_peer_connection_s;
|
||||
|
||||
typedef
|
||||
int (*ngx_http_lua_socket_tcp_retval_handler_masked)(void *r,
|
||||
void *u, void *L);
|
||||
|
||||
typedef void (*ngx_http_lua_socket_tcp_upstream_handler_pt_masked)
|
||||
(void *r, void *u);
|
||||
|
||||
|
||||
typedef
|
||||
int (*ngx_stream_lua_socket_tcp_retval_handler)(void *r,
|
||||
void *u, void *L);
|
||||
|
||||
typedef void (*ngx_stream_lua_socket_tcp_upstream_handler_pt)
|
||||
(void *r, void *u);
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_lua_socket_tcp_retval_handler read_prepare_retvals;
|
||||
ngx_stream_lua_socket_tcp_retval_handler write_prepare_retvals;
|
||||
ngx_stream_lua_socket_tcp_upstream_handler_pt read_event_handler;
|
||||
ngx_stream_lua_socket_tcp_upstream_handler_pt write_event_handler;
|
||||
|
||||
void *socket_pool;
|
||||
|
||||
void *conf;
|
||||
void *cleanup;
|
||||
void *request;
|
||||
|
||||
ngx_peer_connection_s peer;
|
||||
// trimmed
|
||||
} ngx_stream_lua_socket_tcp_upstream_s;
|
||||
]]
|
||||
|
||||
local ngx_lua_version = ngx.config and
|
||||
ngx.config.ngx_lua_version and
|
||||
ngx.config.ngx_lua_version
|
||||
|
||||
if ngx_lua_version >= 10019 and ngx_lua_version <= 10021 then
|
||||
-- https://github.com/openresty/lua-nginx-module/blob/master/src/ngx_http_lua_socket_tcp.h
|
||||
ffi.cdef[[
|
||||
typedef struct {
|
||||
ngx_http_lua_socket_tcp_retval_handler_masked read_prepare_retvals;
|
||||
ngx_http_lua_socket_tcp_retval_handler_masked write_prepare_retvals;
|
||||
ngx_http_lua_socket_tcp_upstream_handler_pt_masked read_event_handler;
|
||||
ngx_http_lua_socket_tcp_upstream_handler_pt_masked write_event_handler;
|
||||
|
||||
void *udata_queue; // 0.10.19
|
||||
|
||||
void *socket_pool;
|
||||
|
||||
void *conf;
|
||||
void *cleanup;
|
||||
void *request;
|
||||
ngx_peer_connection_s peer;
|
||||
// trimmed
|
||||
} ngx_http_lua_socket_tcp_upstream_s;
|
||||
]]
|
||||
elseif ngx_lua_version < 10019 then
|
||||
-- the struct doesn't seem to get changed a long time since birth
|
||||
ffi.cdef[[
|
||||
typedef struct {
|
||||
ngx_http_lua_socket_tcp_retval_handler_masked read_prepare_retvals;
|
||||
ngx_http_lua_socket_tcp_retval_handler_masked write_prepare_retvals;
|
||||
ngx_http_lua_socket_tcp_upstream_handler_pt_masked read_event_handler;
|
||||
ngx_http_lua_socket_tcp_upstream_handler_pt_masked write_event_handler;
|
||||
|
||||
void *socket_pool;
|
||||
|
||||
void *conf;
|
||||
void *cleanup;
|
||||
void *request;
|
||||
ngx_peer_connection_s peer;
|
||||
// trimmed
|
||||
} ngx_http_lua_socket_tcp_upstream_s;
|
||||
]]
|
||||
else
|
||||
error("resty.openssl.auxiliary.nginx doesn't support lua-nginx-module version " .. (ngx_lua_version or "nil"), 2)
|
||||
end
|
||||
|
||||
local function get_ngx_ssl_from_socket_ctx(sock)
|
||||
if not NO_C_MODULE_WARNING_MSG_SHOWN then
|
||||
ngx.log(ngx.WARN, NO_C_MODULE_WARNING_MSG)
|
||||
NO_C_MODULE_WARNING_MSG_SHOWN = true
|
||||
end
|
||||
|
||||
local u = sock[SOCKET_CTX_INDEX]
|
||||
if u == nil then
|
||||
return nil, "lua_socket_tcp_upstream_t not found"
|
||||
end
|
||||
|
||||
if ngx.config.subsystem == "stream" then
|
||||
u = ffi.cast("ngx_stream_lua_socket_tcp_upstream_s*", u)
|
||||
else -- http
|
||||
u = ffi.cast("ngx_http_lua_socket_tcp_upstream_s*", u)
|
||||
end
|
||||
|
||||
local p = u.peer
|
||||
if p == nil then
|
||||
return nil, "u.peer is nil"
|
||||
end
|
||||
|
||||
local uc = p.connection
|
||||
if uc == nil then
|
||||
return nil, "u.peer.connection is nil"
|
||||
end
|
||||
|
||||
local ngx_ssl = uc.ssl
|
||||
if ngx_ssl == nil then
|
||||
return nil, "u.peer.connection.ssl is nil"
|
||||
end
|
||||
return ngx_ssl
|
||||
end
|
||||
|
||||
get_socket_ssl = function(sock)
|
||||
local ssl, err = get_ngx_ssl_from_socket_ctx(sock)
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return ssl.connection
|
||||
end
|
||||
|
||||
get_socket_ssl_ctx = function(sock)
|
||||
local ssl, err = get_ngx_ssl_from_socket_ctx(sock)
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return ssl.session_ctx
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
return {
|
||||
get_req_ssl = get_req_ssl,
|
||||
get_req_ssl_ctx = get_req_ssl_ctx,
|
||||
get_socket_ssl = get_socket_ssl,
|
||||
get_socket_ssl_ctx = get_socket_ssl_ctx,
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
|
||||
local SOCKET_CTX_INDEX = 1
|
||||
local NGX_OK = ngx.OK
|
||||
|
||||
|
||||
local get_req_ssl, get_req_ssl_ctx
|
||||
local get_socket_ssl, get_socket_ssl_ctx
|
||||
|
||||
local get_request
|
||||
do
|
||||
local ok, exdata = pcall(require, "thread.exdata")
|
||||
if ok and exdata then
|
||||
function get_request()
|
||||
local r = exdata()
|
||||
if r ~= nil then
|
||||
return r
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
local getfenv = getfenv
|
||||
|
||||
function get_request()
|
||||
return getfenv(0).__ngx_req
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local stream_subsystem = false
|
||||
if ngx.config.subsystem == "stream" then
|
||||
stream_subsystem = true
|
||||
|
||||
ffi.cdef [[
|
||||
typedef struct ngx_stream_lua_request_s ngx_stream_lua_request_t;
|
||||
typedef struct ngx_stream_lua_socket_tcp_upstream_s ngx_stream_lua_socket_tcp_upstream_t;
|
||||
|
||||
int ngx_stream_lua_resty_openssl_aux_get_request_ssl(ngx_stream_lua_request_t *r,
|
||||
void **_ssl_conn);
|
||||
|
||||
int ngx_stream_lua_resty_openssl_aux_get_request_ssl_ctx(ngx_stream_lua_request_t *r,
|
||||
void **_sess);
|
||||
|
||||
int ngx_stream_lua_resty_openssl_aux_get_socket_ssl(ngx_stream_lua_socket_tcp_upstream_t *u,
|
||||
void **_ssl_conn);
|
||||
|
||||
int ngx_stream_lua_resty_openssl_aux_get_socket_ssl_ctx(ngx_stream_lua_socket_tcp_upstream_t *u,
|
||||
void **_sess);
|
||||
]]
|
||||
|
||||
-- sanity test
|
||||
local _ = C.ngx_stream_lua_resty_openssl_aux_get_request_ssl
|
||||
else
|
||||
ffi.cdef [[
|
||||
typedef struct ngx_http_request_s ngx_http_request_t;
|
||||
typedef struct ngx_http_lua_socket_tcp_upstream_s ngx_http_lua_socket_tcp_upstream_t;
|
||||
|
||||
int ngx_http_lua_resty_openssl_aux_get_request_ssl(ngx_http_request_t *r,
|
||||
void **_ssl_conn);
|
||||
|
||||
int ngx_http_lua_resty_openssl_aux_get_request_ssl_ctx(ngx_http_request_t *r,
|
||||
void **_sess);
|
||||
|
||||
int ngx_http_lua_resty_openssl_aux_get_socket_ssl(ngx_http_lua_socket_tcp_upstream_t *u,
|
||||
void **_ssl_conn);
|
||||
|
||||
int ngx_http_lua_resty_openssl_aux_get_socket_ssl_ctx(ngx_http_lua_socket_tcp_upstream_t *u,
|
||||
void **_sess);
|
||||
]]
|
||||
|
||||
-- sanity test
|
||||
local _ = C.ngx_http_lua_resty_openssl_aux_get_request_ssl
|
||||
end
|
||||
|
||||
local void_pp = ffi.new("void *[1]")
|
||||
local ssl_type = ffi.typeof("SSL*")
|
||||
local ssl_ctx_type = ffi.typeof("SSL_CTX*")
|
||||
|
||||
get_req_ssl = function()
|
||||
local c = get_request()
|
||||
|
||||
local ret
|
||||
if stream_subsystem then
|
||||
ret = C.ngx_stream_lua_resty_openssl_aux_get_request_ssl(c, void_pp)
|
||||
else
|
||||
ret = C.ngx_http_lua_resty_openssl_aux_get_request_ssl(c, void_pp)
|
||||
end
|
||||
|
||||
if ret ~= NGX_OK then
|
||||
return nil, "cannot read r->connection->ssl->connection"
|
||||
end
|
||||
|
||||
return ffi.cast(ssl_type, void_pp[0])
|
||||
end
|
||||
|
||||
get_req_ssl_ctx = function()
|
||||
local c = get_request()
|
||||
|
||||
local ret
|
||||
if stream_subsystem then
|
||||
ret = C.ngx_stream_lua_resty_openssl_aux_get_request_ssl_ctx(c, void_pp)
|
||||
else
|
||||
ret = C.ngx_http_lua_resty_openssl_aux_get_request_ssl_ctx(c, void_pp)
|
||||
end
|
||||
|
||||
if ret ~= NGX_OK then
|
||||
return nil, "cannot read r->connection->ssl->session_ctx"
|
||||
end
|
||||
|
||||
return ffi.cast(ssl_ctx_type, void_pp[0])
|
||||
end
|
||||
|
||||
get_socket_ssl = function(sock)
|
||||
local u = sock[SOCKET_CTX_INDEX]
|
||||
|
||||
local ret
|
||||
if stream_subsystem then
|
||||
ret = C.ngx_stream_lua_resty_openssl_aux_get_socket_ssl(u, void_pp)
|
||||
else
|
||||
ret = C.ngx_http_lua_resty_openssl_aux_get_socket_ssl(u, void_pp)
|
||||
end
|
||||
|
||||
if ret ~= NGX_OK then
|
||||
return nil, "cannot read u->peer.connection->ssl->connection"
|
||||
end
|
||||
|
||||
return ffi.cast(ssl_type, void_pp[0])
|
||||
end
|
||||
|
||||
get_socket_ssl_ctx = function(sock)
|
||||
local u = sock[SOCKET_CTX_INDEX]
|
||||
|
||||
local ret
|
||||
if stream_subsystem then
|
||||
ret = C.ngx_stream_lua_resty_openssl_aux_get_socket_ssl_ctx(u, void_pp)
|
||||
else
|
||||
ret = C.ngx_http_lua_resty_openssl_aux_get_socket_ssl_ctx(u, void_pp)
|
||||
end
|
||||
|
||||
if ret ~= NGX_OK then
|
||||
return nil, "cannot read u->peer.connection->ssl->session_ctx"
|
||||
end
|
||||
|
||||
return ffi.cast(ssl_ctx_type, void_pp[0])
|
||||
end
|
||||
|
||||
return {
|
||||
get_req_ssl = get_req_ssl,
|
||||
get_req_ssl_ctx = get_req_ssl_ctx,
|
||||
get_socket_ssl = get_socket_ssl,
|
||||
get_socket_ssl_ctx = get_socket_ssl_ctx,
|
||||
}
|
|
@ -0,0 +1,435 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
local ffi_gc = ffi.gc
|
||||
local ffi_new = ffi.new
|
||||
local ffi_str = ffi.string
|
||||
local floor = math.floor
|
||||
|
||||
require "resty.openssl.include.bn"
|
||||
local crypto_macro = require("resty.openssl.include.crypto")
|
||||
local ctypes = require "resty.openssl.auxiliary.ctypes"
|
||||
local format_error = require("resty.openssl.err").format_error
|
||||
local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10
|
||||
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X
|
||||
|
||||
local _M = {}
|
||||
local mt = {__index = _M}
|
||||
|
||||
local bn_ptr_ct = ffi.typeof('BIGNUM*')
|
||||
local bn_ptrptr_ct = ffi.typeof('BIGNUM*[1]')
|
||||
|
||||
function _M.new(bn)
|
||||
local ctx = C.BN_new()
|
||||
ffi_gc(ctx, C.BN_free)
|
||||
|
||||
if type(bn) == 'number' then
|
||||
if C.BN_set_word(ctx, bn) ~= 1 then
|
||||
return nil, format_error("bn.new")
|
||||
end
|
||||
elseif bn then
|
||||
return nil, "bn.new: expect nil or a number at #1"
|
||||
end
|
||||
|
||||
return setmetatable( { ctx = ctx }, mt), nil
|
||||
end
|
||||
|
||||
function _M.istype(l)
|
||||
return l and l.ctx and ffi.istype(bn_ptr_ct, l.ctx)
|
||||
end
|
||||
|
||||
function _M.dup(ctx)
|
||||
if not ffi.istype(bn_ptr_ct, ctx) then
|
||||
return nil, "bn.dup: expect a bn ctx at #1"
|
||||
end
|
||||
local ctx = C.BN_dup(ctx)
|
||||
ffi_gc(ctx, C.BN_free)
|
||||
|
||||
local self = setmetatable({
|
||||
ctx = ctx,
|
||||
}, mt)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function _M:to_binary(pad)
|
||||
if pad then
|
||||
if type(pad) ~= "number" then
|
||||
return nil, "bn:to_binary: expect a number at #1"
|
||||
elseif OPENSSL_10 then
|
||||
return nil, "bn:to_binary: padding is only supported on OpenSSL 1.1.0 or later"
|
||||
end
|
||||
end
|
||||
|
||||
local length
|
||||
if not pad then
|
||||
length = (C.BN_num_bits(self.ctx)+7)/8
|
||||
-- align to bytes
|
||||
length = floor(length)
|
||||
else
|
||||
length = pad
|
||||
end
|
||||
|
||||
local buf = ctypes.uchar_array(length)
|
||||
local sz
|
||||
if not pad then
|
||||
sz = C.BN_bn2bin(self.ctx, buf)
|
||||
else
|
||||
sz = C.BN_bn2binpad(self.ctx, buf, pad)
|
||||
end
|
||||
|
||||
if sz <= 0 then
|
||||
return nil, format_error("bn:to_binary")
|
||||
end
|
||||
return ffi_str(buf, sz)
|
||||
end
|
||||
|
||||
function _M.from_binary(s)
|
||||
if type(s) ~= "string" then
|
||||
return nil, "bn.from_binary: expect a string at #1"
|
||||
end
|
||||
|
||||
local ctx = C.BN_bin2bn(s, #s, nil)
|
||||
if ctx == nil then
|
||||
return nil, format_error("bn.from_binary")
|
||||
end
|
||||
ffi_gc(ctx, C.BN_free)
|
||||
return setmetatable( { ctx = ctx }, mt), nil
|
||||
end
|
||||
|
||||
function _M:to_hex()
|
||||
local buf = C.BN_bn2hex(self.ctx)
|
||||
if buf == nil then
|
||||
return nil, format_error("bn:to_hex")
|
||||
end
|
||||
ffi_gc(buf, crypto_macro.OPENSSL_free)
|
||||
local s = ffi_str(buf)
|
||||
return s
|
||||
end
|
||||
|
||||
function _M.from_hex(s)
|
||||
if type(s) ~= "string" then
|
||||
return nil, "bn.from_hex: expect a string at #1"
|
||||
end
|
||||
|
||||
local p = ffi_new(bn_ptrptr_ct)
|
||||
|
||||
if C.BN_hex2bn(p, s) == 0 then
|
||||
return nil, format_error("bn.from_hex")
|
||||
end
|
||||
local ctx = p[0]
|
||||
ffi_gc(ctx, C.BN_free)
|
||||
return setmetatable( { ctx = ctx }, mt), nil
|
||||
end
|
||||
|
||||
function _M:to_dec()
|
||||
local buf = C.BN_bn2dec(self.ctx)
|
||||
if buf == nil then
|
||||
return nil, format_error("bn:to_dec")
|
||||
end
|
||||
ffi_gc(buf, crypto_macro.OPENSSL_free)
|
||||
local s = ffi_str(buf)
|
||||
return s
|
||||
end
|
||||
mt.__tostring = _M.to_dec
|
||||
|
||||
function _M.from_dec(s)
|
||||
if type(s) ~= "string" then
|
||||
return nil, "bn.from_dec: expect a string at #1"
|
||||
end
|
||||
|
||||
local p = ffi_new(bn_ptrptr_ct)
|
||||
|
||||
if C.BN_dec2bn(p, s) == 0 then
|
||||
return nil, format_error("bn.from_dec")
|
||||
end
|
||||
local ctx = p[0]
|
||||
ffi_gc(ctx, C.BN_free)
|
||||
return setmetatable( { ctx = ctx }, mt), nil
|
||||
end
|
||||
|
||||
function _M:to_number()
|
||||
return tonumber(C.BN_get_word(self.ctx))
|
||||
end
|
||||
_M.tonumber = _M.to_number
|
||||
|
||||
function _M.generate_prime(bits, safe)
|
||||
local ctx = C.BN_new()
|
||||
ffi_gc(ctx, C.BN_free)
|
||||
|
||||
if C.BN_generate_prime_ex(ctx, bits, safe and 1 or 0, nil, nil, nil) == 0 then
|
||||
return nil, format_error("bn.BN_generate_prime_ex")
|
||||
end
|
||||
|
||||
return setmetatable( { ctx = ctx }, mt), nil
|
||||
end
|
||||
|
||||
-- BN_CTX is used to store temporary variable
|
||||
-- we only need one per worker
|
||||
local bn_ctx_tmp = C.BN_CTX_new()
|
||||
assert(bn_ctx_tmp ~= nil)
|
||||
if OPENSSL_10 then
|
||||
C.BN_CTX_init(bn_ctx_tmp)
|
||||
end
|
||||
ffi_gc(bn_ctx_tmp, C.BN_CTX_free)
|
||||
|
||||
_M.bn_ctx_tmp = bn_ctx_tmp
|
||||
|
||||
-- mathematics
|
||||
|
||||
local is_negative
|
||||
if OPENSSL_10 then
|
||||
local bn_zero = assert(_M.new(0)).ctx
|
||||
is_negative = function(ctx)
|
||||
return C.BN_cmp(ctx, bn_zero) < 0 and 1 or 0
|
||||
end
|
||||
else
|
||||
is_negative = C.BN_is_negative
|
||||
end
|
||||
function mt.__unm(a)
|
||||
local b = _M.dup(a.ctx)
|
||||
if b == nil then
|
||||
error("BN_dup() failed")
|
||||
end
|
||||
local sign = is_negative(b.ctx)
|
||||
C.BN_set_negative(b.ctx, 1-sign)
|
||||
return b
|
||||
end
|
||||
|
||||
local function check_args(op, ...)
|
||||
local args = {...}
|
||||
for i, arg in ipairs(args) do
|
||||
if type(arg) == 'number' then
|
||||
local b = C.BN_new()
|
||||
if b == nil then
|
||||
error("BN_new() failed")
|
||||
end
|
||||
ffi_gc(b, C.BN_free)
|
||||
if C.BN_set_word(b, arg) ~= 1 then
|
||||
error("BN_set_word() failed")
|
||||
end
|
||||
args[i] = b
|
||||
elseif _M.istype(arg) then
|
||||
args[i] = arg.ctx
|
||||
else
|
||||
error("cannot " .. op .. " a " .. type(arg) .. " to bignum")
|
||||
end
|
||||
end
|
||||
local ctx = C.BN_new()
|
||||
if ctx == nil then
|
||||
error("BN_new() failed")
|
||||
end
|
||||
ffi_gc(ctx, C.BN_free)
|
||||
local r = setmetatable( { ctx = ctx }, mt)
|
||||
return r, unpack(args)
|
||||
end
|
||||
|
||||
|
||||
function mt.__add(...)
|
||||
local r, a, b = check_args("add", ...)
|
||||
if C.BN_add(r.ctx, a, b) == 0 then
|
||||
error("BN_add() failed")
|
||||
end
|
||||
return r
|
||||
end
|
||||
_M.add = mt.__add
|
||||
|
||||
function mt.__sub(...)
|
||||
local r, a, b = check_args("substract", ...)
|
||||
if C.BN_sub(r.ctx, a, b) == 0 then
|
||||
error("BN_sub() failed")
|
||||
end
|
||||
return r
|
||||
end
|
||||
_M.sub = mt.__sub
|
||||
|
||||
function mt.__mul(...)
|
||||
local r, a, b = check_args("multiply", ...)
|
||||
if C.BN_mul(r.ctx, a, b, bn_ctx_tmp) == 0 then
|
||||
error("BN_mul() failed")
|
||||
end
|
||||
return r
|
||||
end
|
||||
_M.mul = mt.__mul
|
||||
|
||||
-- lua 5.3 only
|
||||
function mt.__idiv(...)
|
||||
local r, a, b = check_args("divide", ...)
|
||||
if C.BN_div(r.ctx, nil, a, b, bn_ctx_tmp) == 0 then
|
||||
error("BN_div() failed")
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
mt.__div = mt.__idiv
|
||||
_M.idiv = mt.__idiv
|
||||
_M.div = mt.__div
|
||||
|
||||
function mt.__mod(...)
|
||||
local r, a, b = check_args("mod", ...)
|
||||
if C.BN_div(nil, r.ctx, a, b, bn_ctx_tmp) == 0 then
|
||||
error("BN_div() failed")
|
||||
end
|
||||
return r
|
||||
end
|
||||
_M.mod = mt.__mod
|
||||
|
||||
-- __concat doesn't make sense at all?
|
||||
|
||||
function _M.sqr(...)
|
||||
local r, a = check_args("square", ...)
|
||||
if C.BN_sqr(r.ctx, a, bn_ctx_tmp) == 0 then
|
||||
error("BN_sqr() failed")
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
function _M.gcd(...)
|
||||
local r, a, b = check_args("extract greatest common divisor", ...)
|
||||
if C.BN_gcd(r.ctx, a, b, bn_ctx_tmp) == 0 then
|
||||
error("BN_gcd() failed")
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
function _M.exp(...)
|
||||
local r, a, b = check_args("power", ...)
|
||||
if C.BN_exp(r.ctx, a, b, bn_ctx_tmp) == 0 then
|
||||
error("BN_exp() failed")
|
||||
end
|
||||
return r
|
||||
end
|
||||
_M.pow = _M.exp
|
||||
|
||||
for _, op in ipairs({ "add", "sub" , "mul", "exp" }) do
|
||||
local f = "BN_mod_" .. op
|
||||
local cf = C[f]
|
||||
_M["mod_" .. op] = function(...)
|
||||
local r, a, b, m = check_args(op, ...)
|
||||
if cf(r.ctx, a, b, m, bn_ctx_tmp) == 0 then
|
||||
error(f .. " failed")
|
||||
end
|
||||
return r
|
||||
end
|
||||
end
|
||||
|
||||
function _M.mod_sqr(...)
|
||||
local r, a, m = check_args("mod_sub", ...)
|
||||
if C.BN_mod_sqr(r.ctx, a, m, bn_ctx_tmp) == 0 then
|
||||
error("BN_mod_sqr() failed")
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
local function nyi()
|
||||
error("NYI")
|
||||
end
|
||||
|
||||
-- bit operations, lua 5.3
|
||||
|
||||
mt.__band = nyi
|
||||
mt.__bor = nyi
|
||||
mt.__bxor = nyi
|
||||
mt.__bnot = nyi
|
||||
|
||||
function mt.__shl(a, b)
|
||||
local r, a = check_args("lshift", a)
|
||||
if C.BN_lshift(r.ctx, a, b) == 0 then
|
||||
error("BN_lshift() failed")
|
||||
end
|
||||
return r
|
||||
end
|
||||
_M.lshift = mt.__shl
|
||||
|
||||
function mt.__shr(a, b)
|
||||
local r, a = check_args("rshift", a)
|
||||
if C.BN_rshift(r.ctx, a, b) == 0 then
|
||||
error("BN_lshift() failed")
|
||||
end
|
||||
return r
|
||||
end
|
||||
_M.rshift = mt.__shr
|
||||
|
||||
-- comparaions
|
||||
-- those functions are only called when the table
|
||||
-- has exact same metamethods, i.e. they are all BN
|
||||
-- so we don't need to check args
|
||||
|
||||
function mt.__eq(a, b)
|
||||
return C.BN_cmp(a.ctx, b.ctx) == 0
|
||||
end
|
||||
|
||||
function mt.__lt(a, b)
|
||||
return C.BN_cmp(a.ctx, b.ctx) < 0
|
||||
end
|
||||
|
||||
function mt.__le(a, b)
|
||||
return C.BN_cmp(a.ctx, b.ctx) <= 0
|
||||
end
|
||||
|
||||
if OPENSSL_10 then
|
||||
-- in openssl 1.0.x those functions are implemented as macros
|
||||
-- don't want to copy paste all structs here
|
||||
-- the followings are definitely slower, but works
|
||||
local bn_zero = assert(_M.new(0)).ctx
|
||||
local bn_one = assert(_M.new(1)).ctx
|
||||
|
||||
function _M:is_zero()
|
||||
return C.BN_cmp(self.ctx, bn_zero) == 0
|
||||
end
|
||||
|
||||
function _M:is_one()
|
||||
return C.BN_cmp(self.ctx, bn_one) == 0
|
||||
end
|
||||
|
||||
function _M:is_word(n)
|
||||
local ctx = C.BN_new()
|
||||
ffi_gc(ctx, C.BN_free)
|
||||
if ctx == nil then
|
||||
return nil, "bn:is_word: BN_new() failed"
|
||||
end
|
||||
if C.BN_set_word(ctx, n) ~= 1 then
|
||||
return nil, "bn:is_word: BN_set_word() failed"
|
||||
end
|
||||
return C.BN_cmp(self.ctx, ctx) == 0
|
||||
end
|
||||
|
||||
function _M:is_odd()
|
||||
return self:to_number() % 2 == 1
|
||||
end
|
||||
else
|
||||
function _M:is_zero()
|
||||
return C.BN_is_zero(self.ctx) == 1
|
||||
end
|
||||
|
||||
function _M:is_one()
|
||||
return C.BN_is_one(self.ctx) == 1
|
||||
end
|
||||
|
||||
function _M:is_word(n)
|
||||
return C.BN_is_word(self.ctx, n) == 1
|
||||
end
|
||||
|
||||
function _M:is_odd()
|
||||
return C.BN_is_odd(self.ctx) == 1
|
||||
end
|
||||
end
|
||||
|
||||
function _M:is_prime(nchecks)
|
||||
if nchecks and type(nchecks) ~= "number" then
|
||||
return nil, "bn:is_prime: expect a number at #1"
|
||||
end
|
||||
-- if nchecks is not defined, set to BN_prime_checks:
|
||||
-- select number of iterations based on the size of the number
|
||||
local code
|
||||
if OPENSSL_3X then
|
||||
code = C.BN_check_prime(self.ctx, bn_ctx_tmp, nil)
|
||||
else
|
||||
code = C.BN_is_prime_ex(self.ctx, nchecks or 0, bn_ctx_tmp, nil)
|
||||
end
|
||||
if code == -1 then
|
||||
return nil, format_error("bn.is_prime")
|
||||
end
|
||||
return code == 1
|
||||
end
|
||||
|
||||
return _M
|
|
@ -0,0 +1,300 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
local ffi_gc = ffi.gc
|
||||
local ffi_str = ffi.string
|
||||
local ffi_cast = ffi.cast
|
||||
|
||||
require "resty.openssl.include.evp.cipher"
|
||||
local evp_macro = require "resty.openssl.include.evp"
|
||||
local ctypes = require "resty.openssl.auxiliary.ctypes"
|
||||
local ctx_lib = require "resty.openssl.ctx"
|
||||
local format_error = require("resty.openssl.err").format_error
|
||||
local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10
|
||||
local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER
|
||||
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X
|
||||
|
||||
local uchar_array = ctypes.uchar_array
|
||||
local void_ptr = ctypes.void_ptr
|
||||
local ptr_of_int = ctypes.ptr_of_int
|
||||
local uchar_ptr = ctypes.uchar_ptr
|
||||
|
||||
local _M = {}
|
||||
local mt = {__index = _M}
|
||||
|
||||
local cipher_ctx_ptr_ct = ffi.typeof('EVP_CIPHER_CTX*')
|
||||
|
||||
local out_length = ptr_of_int()
|
||||
-- EVP_MAX_BLOCK_LENGTH is 32, we give it a 64 to be future proof
|
||||
local out_buffer = ctypes.uchar_array(1024 + 64)
|
||||
|
||||
function _M.new(typ, properties)
|
||||
if not typ then
|
||||
return nil, "cipher.new: expect type to be defined"
|
||||
end
|
||||
|
||||
local ctx
|
||||
if OPENSSL_11_OR_LATER then
|
||||
ctx = C.EVP_CIPHER_CTX_new()
|
||||
ffi_gc(ctx, C.EVP_CIPHER_CTX_free)
|
||||
elseif OPENSSL_10 then
|
||||
ctx = ffi.new('EVP_CIPHER_CTX')
|
||||
C.EVP_CIPHER_CTX_init(ctx)
|
||||
ffi_gc(ctx, C.EVP_CIPHER_CTX_cleanup)
|
||||
end
|
||||
if ctx == nil then
|
||||
return nil, "cipher.new: failed to create EVP_CIPHER_CTX"
|
||||
end
|
||||
|
||||
local ctyp
|
||||
if OPENSSL_3X then
|
||||
ctyp = C.EVP_CIPHER_fetch(ctx_lib.get_libctx(), typ, properties)
|
||||
else
|
||||
ctyp = C.EVP_get_cipherbyname(typ)
|
||||
end
|
||||
local err_new = string.format("cipher.new: invalid cipher type \"%s\"", typ)
|
||||
if ctyp == nil then
|
||||
return nil, format_error(err_new)
|
||||
end
|
||||
|
||||
local code = C.EVP_CipherInit_ex(ctx, ctyp, nil, "", nil, -1)
|
||||
if code ~= 1 then
|
||||
return nil, format_error(err_new)
|
||||
end
|
||||
|
||||
return setmetatable({
|
||||
ctx = ctx,
|
||||
algo = ctyp,
|
||||
initialized = false,
|
||||
block_size = tonumber(OPENSSL_3X and C.EVP_CIPHER_CTX_get_block_size(ctx)
|
||||
or C.EVP_CIPHER_CTX_block_size(ctx)),
|
||||
key_size = tonumber(OPENSSL_3X and C.EVP_CIPHER_CTX_get_key_length(ctx)
|
||||
or C.EVP_CIPHER_CTX_key_length(ctx)),
|
||||
iv_size = tonumber(OPENSSL_3X and C.EVP_CIPHER_CTX_get_iv_length(ctx)
|
||||
or C.EVP_CIPHER_CTX_iv_length(ctx)),
|
||||
}, mt), nil
|
||||
end
|
||||
|
||||
function _M.istype(l)
|
||||
return l and l.ctx and ffi.istype(cipher_ctx_ptr_ct, l.ctx)
|
||||
end
|
||||
|
||||
function _M:get_provider_name()
|
||||
if not OPENSSL_3X then
|
||||
return false, "cipher:get_provider_name is not supported"
|
||||
end
|
||||
local p = C.EVP_CIPHER_get0_provider(self.algo)
|
||||
if p == nil then
|
||||
return nil
|
||||
end
|
||||
return ffi_str(C.OSSL_PROVIDER_get0_name(p))
|
||||
end
|
||||
|
||||
if OPENSSL_3X then
|
||||
local param_lib = require "resty.openssl.param"
|
||||
_M.settable_params, _M.set_params, _M.gettable_params, _M.get_param = param_lib.get_params_func("EVP_CIPHER_CTX")
|
||||
end
|
||||
|
||||
function _M:init(key, iv, opts)
|
||||
opts = opts or {}
|
||||
if not key or #key ~= self.key_size then
|
||||
return false, string.format("cipher:init: incorrect key size, expect %d", self.key_size)
|
||||
end
|
||||
if not iv or #iv ~= self.iv_size then
|
||||
return false, string.format("cipher:init: incorrect iv size, expect %d", self.iv_size)
|
||||
end
|
||||
|
||||
-- always passed in the `EVP_CIPHER` parameter to reinitialized the cipher
|
||||
-- it will have a same effect as EVP_CIPHER_CTX_cleanup/EVP_CIPHER_CTX_reset then Init_ex with
|
||||
-- empty algo
|
||||
if C.EVP_CipherInit_ex(self.ctx, self.algo, nil, key, iv, opts.is_encrypt and 1 or 0) == 0 then
|
||||
return false, format_error("cipher:init EVP_CipherInit_ex")
|
||||
end
|
||||
|
||||
if opts.no_padding then
|
||||
-- EVP_CIPHER_CTX_set_padding() always returns 1.
|
||||
C.EVP_CIPHER_CTX_set_padding(self.ctx, 0)
|
||||
end
|
||||
|
||||
self.initialized = true
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function _M:encrypt(key, iv, s, no_padding, aead_aad)
|
||||
local _, err = self:init(key, iv, {
|
||||
is_encrypt = true,
|
||||
no_padding = no_padding,
|
||||
})
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
if aead_aad then
|
||||
local _, err = self:update_aead_aad(aead_aad)
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
return self:final(s)
|
||||
end
|
||||
|
||||
function _M:decrypt(key, iv, s, no_padding, aead_aad, aead_tag)
|
||||
local _, err = self:init(key, iv, {
|
||||
is_encrypt = false,
|
||||
no_padding = no_padding,
|
||||
})
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
if aead_aad then
|
||||
local _, err = self:update_aead_aad(aead_aad)
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
if aead_tag then
|
||||
local _, err = self:set_aead_tag(aead_tag)
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
return self:final(s)
|
||||
end
|
||||
|
||||
-- https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption
|
||||
function _M:update_aead_aad(aad)
|
||||
if not self.initialized then
|
||||
return nil, "cipher:update_aead_aad: cipher not initalized, call cipher:init first"
|
||||
end
|
||||
|
||||
if C.EVP_CipherUpdate(self.ctx, nil, out_length, aad, #aad) ~= 1 then
|
||||
return false, format_error("cipher:update_aead_aad")
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function _M:get_aead_tag(size)
|
||||
if not self.initialized then
|
||||
return nil, "cipher:get_aead_tag: cipher not initalized, call cipher:init first"
|
||||
end
|
||||
|
||||
size = size or self.key_size / 2
|
||||
if size > self.key_size then
|
||||
return nil, string.format("tag size %d is too large", size)
|
||||
end
|
||||
if C.EVP_CIPHER_CTX_ctrl(self.ctx, evp_macro.EVP_CTRL_AEAD_GET_TAG, size, out_buffer) ~= 1 then
|
||||
return nil, format_error("cipher:get_aead_tag")
|
||||
end
|
||||
|
||||
return ffi_str(out_buffer, size)
|
||||
end
|
||||
|
||||
function _M:set_aead_tag(tag)
|
||||
if not self.initialized then
|
||||
return nil, "cipher:set_aead_tag: cipher not initalized, call cipher:init first"
|
||||
end
|
||||
|
||||
if type(tag) ~= "string" then
|
||||
return false, "cipher:set_aead_tag expect a string at #1"
|
||||
end
|
||||
local tag_void_ptr = ffi_cast(void_ptr, tag)
|
||||
if C.EVP_CIPHER_CTX_ctrl(self.ctx, evp_macro.EVP_CTRL_AEAD_SET_TAG, #tag, tag_void_ptr) ~= 1 then
|
||||
return false, format_error("cipher:set_aead_tag")
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function _M:update(...)
|
||||
if not self.initialized then
|
||||
return nil, "cipher:update: cipher not initalized, call cipher:init first"
|
||||
end
|
||||
|
||||
local ret = {}
|
||||
for i, s in ipairs({...}) do
|
||||
local inl = #s
|
||||
if inl > 1024 then
|
||||
s = ffi_cast(uchar_ptr, s)
|
||||
for i=0, inl-1, 1024 do
|
||||
local chunk_size = 1024
|
||||
if inl - i < 1024 then
|
||||
chunk_size = inl - i
|
||||
end
|
||||
if C.EVP_CipherUpdate(self.ctx, out_buffer, out_length, s+i, chunk_size) ~= 1 then
|
||||
return nil, format_error("cipher:update")
|
||||
end
|
||||
table.insert(ret, ffi_str(out_buffer, out_length[0]))
|
||||
end
|
||||
else
|
||||
if C.EVP_CipherUpdate(self.ctx, out_buffer, out_length, s, inl) ~= 1 then
|
||||
return nil, format_error("cipher:update")
|
||||
end
|
||||
table.insert(ret, ffi_str(out_buffer, out_length[0]))
|
||||
end
|
||||
end
|
||||
return table.concat(ret, "")
|
||||
end
|
||||
|
||||
function _M:final(s)
|
||||
local ret, err
|
||||
if s then
|
||||
ret, err = self:update(s)
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
if C.EVP_CipherFinal_ex(self.ctx, out_buffer, out_length) ~= 1 then
|
||||
return nil, format_error("cipher:final: EVP_CipherFinal_ex")
|
||||
end
|
||||
local final_ret = ffi_str(out_buffer, out_length[0])
|
||||
return ret and (ret .. final_ret) or final_ret
|
||||
end
|
||||
|
||||
|
||||
function _M:derive(key, salt, count, md, md_properties)
|
||||
if type(key) ~= "string" then
|
||||
return nil, nil, "cipher:derive: expect a string at #1"
|
||||
elseif salt and type(salt) ~= "string" then
|
||||
return nil, nil, "cipher:derive: expect a string at #2"
|
||||
elseif count then
|
||||
count = tonumber(count)
|
||||
if not count then
|
||||
return nil, nil, "cipher:derive: expect a number at #3"
|
||||
end
|
||||
elseif md and type(md) ~= "string" then
|
||||
return nil, nil, "cipher:derive: expect a string or nil at #4"
|
||||
end
|
||||
|
||||
if salt then
|
||||
if #salt > 8 then
|
||||
ngx.log(ngx.WARN, "cipher:derive: salt is too long, truncate salt to 8 bytes")
|
||||
salt = salt:sub(0, 8)
|
||||
elseif #salt < 8 then
|
||||
ngx.log(ngx.WARN, "cipher:derive: salt is too short, padding with zero bytes to length")
|
||||
salt = salt .. string.rep('\000', 8 - #salt)
|
||||
end
|
||||
end
|
||||
|
||||
local mdt
|
||||
if OPENSSL_3X then
|
||||
mdt = C.EVP_MD_fetch(ctx_lib.get_libctx(), md or 'sha1', md_properties)
|
||||
else
|
||||
mdt = C.EVP_get_digestbyname(md or 'sha1')
|
||||
end
|
||||
if mdt == nil then
|
||||
return nil, nil, string.format("cipher:derive: invalid digest type \"%s\"", md)
|
||||
end
|
||||
local cipt = C.EVP_CIPHER_CTX_cipher(self.ctx)
|
||||
local keyb = uchar_array(self.key_size)
|
||||
local ivb = uchar_array(self.iv_size)
|
||||
|
||||
local size = C.EVP_BytesToKey(cipt, mdt, salt,
|
||||
key, #key, count or 1,
|
||||
keyb, ivb)
|
||||
if size == 0 then
|
||||
return nil, nil, format_error("cipher:derive: EVP_BytesToKey")
|
||||
end
|
||||
|
||||
return ffi_str(keyb, size), ffi_str(ivb, self.iv_size)
|
||||
end
|
||||
|
||||
return _M
|
|
@ -0,0 +1,78 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
local ffi_gc = ffi.gc
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
local format_error = require("resty.openssl.err").format_error
|
||||
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X
|
||||
|
||||
ffi.cdef [[
|
||||
OSSL_LIB_CTX *OSSL_LIB_CTX_new(void);
|
||||
int OSSL_LIB_CTX_load_config(OSSL_LIB_CTX *ctx, const char *config_file);
|
||||
void OSSL_LIB_CTX_free(OSSL_LIB_CTX *ctx);
|
||||
]]
|
||||
|
||||
local ossl_lib_ctx
|
||||
|
||||
local function new(request_context_only, conf_file)
|
||||
if not OPENSSL_3X then
|
||||
return false, "ctx is only supported from OpenSSL 3.0"
|
||||
end
|
||||
|
||||
local ctx = C.OSSL_LIB_CTX_new()
|
||||
ffi_gc(ctx, C.OSSL_LIB_CTX_free)
|
||||
|
||||
if conf_file and C.OSSL_LIB_CTX_load_config(ctx, conf_file) ~= 1 then
|
||||
return false, format_error("ctx.new")
|
||||
end
|
||||
|
||||
if request_context_only then
|
||||
ngx.ctx.ossl_lib_ctx = ctx
|
||||
else
|
||||
ossl_lib_ctx = ctx
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function free(request_context_only)
|
||||
if not OPENSSL_3X then
|
||||
return false, "ctx is only supported from OpenSSL 3.0"
|
||||
end
|
||||
|
||||
if request_context_only then
|
||||
ngx.ctx.ossl_lib_ctx = nil
|
||||
else
|
||||
ossl_lib_ctx = nil
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local test_request
|
||||
|
||||
do
|
||||
|
||||
local ok, exdata = pcall(require, "thread.exdata")
|
||||
if ok and exdata then
|
||||
test_request = function()
|
||||
local r = exdata()
|
||||
if r ~= nil then
|
||||
return not not r
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
local getfenv = getfenv
|
||||
|
||||
function test_request()
|
||||
return not not getfenv(0).__ngx_req
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
new = new,
|
||||
free = free,
|
||||
get_libctx = function() return test_request() and ngx.ctx.ossl_lib_ctx or ossl_lib_ctx end,
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
|
||||
require "resty.openssl.include.dh"
|
||||
local bn_lib = require "resty.openssl.bn"
|
||||
|
||||
local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10
|
||||
local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER
|
||||
local format_error = require("resty.openssl.err").format_error
|
||||
|
||||
local _M = {}
|
||||
|
||||
_M.params = {"public", "private", "p", "q", "g"}
|
||||
|
||||
local empty_table = {}
|
||||
local bn_ptrptr_ct = ffi.typeof("const BIGNUM *[1]")
|
||||
function _M.get_parameters(dh_st)
|
||||
return setmetatable(empty_table, {
|
||||
__index = function(_, k)
|
||||
local ptr, ret
|
||||
if OPENSSL_11_OR_LATER then
|
||||
ptr = bn_ptrptr_ct()
|
||||
end
|
||||
|
||||
if OPENSSL_11_OR_LATER then
|
||||
ptr = bn_ptrptr_ct()
|
||||
end
|
||||
|
||||
if k == 'p' then
|
||||
if OPENSSL_11_OR_LATER then
|
||||
C.DH_get0_pqg(dh_st, ptr, nil, nil)
|
||||
end
|
||||
elseif k == 'q' then
|
||||
if OPENSSL_11_OR_LATER then
|
||||
C.DH_get0_pqg(dh_st, nil, ptr, nil)
|
||||
end
|
||||
elseif k == 'g' then
|
||||
if OPENSSL_11_OR_LATER then
|
||||
C.DH_get0_pqg(dh_st, nil, nil, ptr)
|
||||
end
|
||||
elseif k == 'public' then
|
||||
if OPENSSL_11_OR_LATER then
|
||||
C.DH_get0_key(dh_st, ptr, nil)
|
||||
end
|
||||
k = "pub_key"
|
||||
elseif k == 'private' then
|
||||
if OPENSSL_11_OR_LATER then
|
||||
C.DH_get0_key(dh_st, nil, ptr)
|
||||
end
|
||||
k = "priv_key"
|
||||
else
|
||||
return nil, "rsa.get_parameters: unknown parameter \"" .. k .. "\" for RSA key"
|
||||
end
|
||||
|
||||
if OPENSSL_11_OR_LATER then
|
||||
ret = ptr[0]
|
||||
elseif OPENSSL_10 then
|
||||
ret = dh_st[k]
|
||||
end
|
||||
|
||||
if ret == nil then
|
||||
return nil
|
||||
end
|
||||
return bn_lib.dup(ret)
|
||||
end
|
||||
}), nil
|
||||
end
|
||||
|
||||
local function dup_bn_value(v)
|
||||
if not bn_lib.istype(v) then
|
||||
return nil, "expect value to be a bn instance"
|
||||
end
|
||||
local bn = C.BN_dup(v.ctx)
|
||||
if bn == nil then
|
||||
return nil, "BN_dup() failed"
|
||||
end
|
||||
return bn
|
||||
end
|
||||
|
||||
function _M.set_parameters(dh_st, opts)
|
||||
local err
|
||||
local opts_bn = {}
|
||||
-- remember which parts of BNs has been added to dh_st, they should be freed
|
||||
-- by DH_free and we don't cleanup them on failure
|
||||
local cleanup_from_idx = 1
|
||||
-- dup input
|
||||
local do_set_key, do_set_pqg
|
||||
for k, v in pairs(opts) do
|
||||
opts_bn[k], err = dup_bn_value(v)
|
||||
if err then
|
||||
err = "dh.set_parameters: cannot process parameter \"" .. k .. "\":" .. err
|
||||
goto cleanup_with_error
|
||||
end
|
||||
if k == "private" or k == "public" then
|
||||
do_set_key = true
|
||||
elseif k == "p" or k == "q" or k == "g" then
|
||||
do_set_pqg = true
|
||||
end
|
||||
end
|
||||
if OPENSSL_11_OR_LATER then
|
||||
local code
|
||||
if do_set_key then
|
||||
code = C.DH_set0_key(dh_st, opts_bn["public"], opts_bn["private"])
|
||||
if code == 0 then
|
||||
err = format_error("dh.set_parameters: DH_set0_key")
|
||||
goto cleanup_with_error
|
||||
end
|
||||
end
|
||||
cleanup_from_idx = cleanup_from_idx + 2
|
||||
if do_set_pqg then
|
||||
code = C.DH_set0_pqg(dh_st, opts_bn["p"], opts_bn["q"], opts_bn["g"])
|
||||
if code == 0 then
|
||||
err = format_error("dh.set_parameters: DH_set0_pqg")
|
||||
goto cleanup_with_error
|
||||
end
|
||||
end
|
||||
return true
|
||||
elseif OPENSSL_10 then
|
||||
for k, v in pairs(opts_bn) do
|
||||
if k == "public" then
|
||||
k = "pub_key"
|
||||
elseif k == "private" then
|
||||
k = "priv_key"
|
||||
end
|
||||
if dh_st[k] ~= nil then
|
||||
C.BN_free(dh_st[k])
|
||||
end
|
||||
dh_st[k]= v
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
::cleanup_with_error::
|
||||
for i, k in pairs(_M.params) do
|
||||
if i >= cleanup_from_idx then
|
||||
C.BN_free(opts_bn[k])
|
||||
end
|
||||
end
|
||||
return false, err
|
||||
end
|
||||
|
||||
return _M
|
|
@ -0,0 +1,116 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
local ffi_gc = ffi.gc
|
||||
local ffi_str = ffi.string
|
||||
|
||||
require "resty.openssl.include.evp.md"
|
||||
local ctypes = require "resty.openssl.auxiliary.ctypes"
|
||||
local ctx_lib = require "resty.openssl.ctx"
|
||||
local format_error = require("resty.openssl.err").format_error
|
||||
local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10
|
||||
local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER
|
||||
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X
|
||||
|
||||
local _M = {}
|
||||
local mt = {__index = _M}
|
||||
|
||||
local md_ctx_ptr_ct = ffi.typeof('EVP_MD_CTX*')
|
||||
|
||||
function _M.new(typ, properties)
|
||||
local ctx
|
||||
if OPENSSL_11_OR_LATER then
|
||||
ctx = C.EVP_MD_CTX_new()
|
||||
ffi_gc(ctx, C.EVP_MD_CTX_free)
|
||||
elseif OPENSSL_10 then
|
||||
ctx = C.EVP_MD_CTX_create()
|
||||
ffi_gc(ctx, C.EVP_MD_CTX_destroy)
|
||||
end
|
||||
if ctx == nil then
|
||||
return nil, "digest.new: failed to create EVP_MD_CTX"
|
||||
end
|
||||
|
||||
local err_new = string.format("digest.new: invalid digest type \"%s\"", typ)
|
||||
|
||||
local algo
|
||||
if typ == "null" then
|
||||
algo = C.EVP_md_null()
|
||||
else
|
||||
if OPENSSL_3X then
|
||||
algo = C.EVP_MD_fetch(ctx_lib.get_libctx(), typ or 'sha1', properties)
|
||||
else
|
||||
algo = C.EVP_get_digestbyname(typ or 'sha1')
|
||||
end
|
||||
if algo == nil then
|
||||
return nil, format_error(err_new)
|
||||
end
|
||||
end
|
||||
|
||||
local code = C.EVP_DigestInit_ex(ctx, algo, nil)
|
||||
if code ~= 1 then
|
||||
return nil, format_error(err_new)
|
||||
end
|
||||
|
||||
return setmetatable({
|
||||
ctx = ctx,
|
||||
algo = algo,
|
||||
buf = ctypes.uchar_array(OPENSSL_3X and C.EVP_MD_get_size(algo) or C.EVP_MD_size(algo)),
|
||||
}, mt), nil
|
||||
end
|
||||
|
||||
function _M.istype(l)
|
||||
return l and l.ctx and ffi.istype(md_ctx_ptr_ct, l.ctx)
|
||||
end
|
||||
|
||||
function _M:get_provider_name()
|
||||
if not OPENSSL_3X then
|
||||
return false, "digest:get_provider_name is not supported"
|
||||
end
|
||||
local p = C.EVP_MD_get0_provider(self.algo)
|
||||
if p == nil then
|
||||
return nil
|
||||
end
|
||||
return ffi_str(C.OSSL_PROVIDER_get0_name(p))
|
||||
end
|
||||
|
||||
if OPENSSL_3X then
|
||||
local param_lib = require "resty.openssl.param"
|
||||
_M.settable_params, _M.set_params, _M.gettable_params, _M.get_param = param_lib.get_params_func("EVP_MD_CTX")
|
||||
end
|
||||
|
||||
function _M:update(...)
|
||||
for _, s in ipairs({...}) do
|
||||
if C.EVP_DigestUpdate(self.ctx, s, #s) ~= 1 then
|
||||
return false, format_error("digest:update")
|
||||
end
|
||||
end
|
||||
return true, nil
|
||||
end
|
||||
|
||||
local result_length = ctypes.ptr_of_uint()
|
||||
|
||||
function _M:final(s)
|
||||
if s then
|
||||
if C.EVP_DigestUpdate(self.ctx, s, #s) ~= 1 then
|
||||
return false, format_error("digest:final")
|
||||
end
|
||||
end
|
||||
|
||||
-- no return value of EVP_DigestFinal_ex
|
||||
C.EVP_DigestFinal_ex(self.ctx, self.buf, result_length)
|
||||
if result_length[0] == nil or result_length[0] <= 0 then
|
||||
return nil, format_error("digest:final: EVP_DigestFinal_ex")
|
||||
end
|
||||
return ffi_str(self.buf, result_length[0])
|
||||
end
|
||||
|
||||
|
||||
function _M:reset()
|
||||
local code = C.EVP_DigestInit_ex(self.ctx, self.algo, nil)
|
||||
if code ~= 1 then
|
||||
return false, format_error("digest:reset")
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return _M
|
|
@ -0,0 +1,186 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
local ffi_gc = ffi.gc
|
||||
|
||||
require "resty.openssl.include.ec"
|
||||
local bn_lib = require "resty.openssl.bn"
|
||||
local objects_lib = require "resty.openssl.objects"
|
||||
local ctypes = require "resty.openssl.auxiliary.ctypes"
|
||||
|
||||
local version_num = require("resty.openssl.version").version_num
|
||||
local format_error = require("resty.openssl.err").format_error
|
||||
local BORINGSSL = require("resty.openssl.version").BORINGSSL
|
||||
|
||||
local _M = {}
|
||||
|
||||
_M.params = {"group", "public", "private", "x", "y"}
|
||||
|
||||
local empty_table = {}
|
||||
|
||||
function _M.get_parameters(ec_key_st)
|
||||
return setmetatable(empty_table, {
|
||||
__index = function(_, k)
|
||||
local group = C.EC_KEY_get0_group(ec_key_st)
|
||||
local bn
|
||||
|
||||
if k == 'group' then
|
||||
local nid = C.EC_GROUP_get_curve_name(group)
|
||||
if nid == 0 then
|
||||
return nil, "ec.get_parameters: EC_GROUP_get_curve_name() failed"
|
||||
end
|
||||
return nid
|
||||
elseif k == 'public' or k == "pub_key" then
|
||||
local pub_point = C.EC_KEY_get0_public_key(ec_key_st)
|
||||
if pub_point == nil then
|
||||
return nil, format_error("ec.get_parameters: EC_KEY_get0_public_key")
|
||||
end
|
||||
local point_form = C.EC_KEY_get_conv_form(ec_key_st)
|
||||
if point_form == nil then
|
||||
return nil, format_error("ec.get_parameters: EC_KEY_get_conv_form")
|
||||
end
|
||||
if BORINGSSL then
|
||||
local sz = tonumber(C.EC_POINT_point2oct(group, pub_point, point_form, nil, 0, bn_lib.bn_ctx_tmp))
|
||||
if sz <= 0 then
|
||||
return nil, format_error("ec.get_parameters: EC_POINT_point2oct")
|
||||
end
|
||||
local buf = ctypes.uchar_array(sz)
|
||||
C.EC_POINT_point2oct(group, pub_point, point_form, buf, sz, bn_lib.bn_ctx_tmp)
|
||||
buf = ffi.string(buf, sz)
|
||||
local err
|
||||
bn, err = bn_lib.from_binary(buf)
|
||||
if bn == nil then
|
||||
return nil, "ec.get_parameters: bn_lib.from_binary: " .. err
|
||||
end
|
||||
return bn
|
||||
else
|
||||
bn = C.EC_POINT_point2bn(group, pub_point, point_form, nil, bn_lib.bn_ctx_tmp)
|
||||
if bn == nil then
|
||||
return nil, format_error("ec.get_parameters: EC_POINT_point2bn")
|
||||
end
|
||||
ffi_gc(bn, C.BN_free)
|
||||
end
|
||||
elseif k == 'private' or k == "priv_key" then
|
||||
-- get0, don't GC
|
||||
bn = C.EC_KEY_get0_private_key(ec_key_st)
|
||||
elseif k == 'x' or k == 'y' then
|
||||
local pub_point = C.EC_KEY_get0_public_key(ec_key_st)
|
||||
if pub_point == nil then
|
||||
return nil, format_error("ec.get_parameters: EC_KEY_get0_public_key")
|
||||
end
|
||||
bn = C.BN_new()
|
||||
if bn == nil then
|
||||
return nil, "ec.get_parameters: BN_new() failed"
|
||||
end
|
||||
ffi_gc(bn, C.BN_free)
|
||||
local f
|
||||
if version_num >= 0x10101000 then
|
||||
f = C.EC_POINT_get_affine_coordinates
|
||||
else
|
||||
f = C.EC_POINT_get_affine_coordinates_GFp
|
||||
end
|
||||
local code
|
||||
if k == 'x' then
|
||||
code = f(group, pub_point, bn, nil, bn_lib.bn_ctx_tmp)
|
||||
else
|
||||
code = f(group, pub_point, nil, bn, bn_lib.bn_ctx_tmp)
|
||||
end
|
||||
if code ~= 1 then
|
||||
return nil, format_error("ec.get_parameters: EC_POINT_get_affine_coordinates")
|
||||
end
|
||||
else
|
||||
return nil, "ec.get_parameters: unknown parameter \"" .. k .. "\" for EC key"
|
||||
end
|
||||
|
||||
if bn == nil then
|
||||
return nil
|
||||
end
|
||||
return bn_lib.dup(bn)
|
||||
end
|
||||
}), nil
|
||||
end
|
||||
|
||||
function _M.set_parameters(ec_key_st, opts)
|
||||
for _, k in ipairs(_M.params) do
|
||||
if k ~= "group" then
|
||||
if opts[k] and not bn_lib.istype(opts[k]) then
|
||||
return nil, "expect parameter \"" .. k .. "\" to be a bn instance"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local group_nid = opts["group"]
|
||||
local group
|
||||
if group_nid then
|
||||
local nid, err = objects_lib.txtnid2nid(group_nid)
|
||||
if err then
|
||||
return nil, "ec.set_parameters: cannot use parameter \"group\":" .. err
|
||||
end
|
||||
|
||||
group = C.EC_GROUP_new_by_curve_name(nid)
|
||||
if group == nil then
|
||||
return nil, "ec.set_parameters: EC_GROUP_new_by_curve_name() failed"
|
||||
end
|
||||
ffi_gc(group, C.EC_GROUP_free)
|
||||
-- # define OPENSSL_EC_NAMED_CURVE 0x001
|
||||
C.EC_GROUP_set_asn1_flag(group, 1)
|
||||
C.EC_GROUP_set_point_conversion_form(group, C.POINT_CONVERSION_UNCOMPRESSED)
|
||||
|
||||
if C.EC_KEY_set_group(ec_key_st, group) ~= 1 then
|
||||
return nil, format_error("ec.set_parameters: EC_KEY_set_group")
|
||||
end
|
||||
end
|
||||
|
||||
local x = opts["x"]
|
||||
local y = opts["y"]
|
||||
local pub = opts["public"]
|
||||
if (x and not y) or (y and not x) then
|
||||
return nil, "ec.set_parameters: \"x\" and \"y\" parameter must be defined at same time or both undefined"
|
||||
end
|
||||
|
||||
if x and y then
|
||||
if pub then
|
||||
return nil, "ec.set_parameters: cannot set \"x\" and \"y\" with \"public\" at same time to set public key"
|
||||
end
|
||||
-- double check if we have set group already
|
||||
if group == nil then
|
||||
group = C.EC_KEY_get0_group(ec_key_st)
|
||||
if group == nil then
|
||||
return nil, "ec.set_parameters: cannot set public key without setting \"group\""
|
||||
end
|
||||
end
|
||||
|
||||
if C.EC_KEY_set_public_key_affine_coordinates(ec_key_st, x.ctx, y.ctx) ~= 1 then
|
||||
return nil, format_error("ec.set_parameters: EC_KEY_set_public_key_affine_coordinates")
|
||||
end
|
||||
end
|
||||
|
||||
if pub then
|
||||
if group == nil then
|
||||
group = C.EC_KEY_get0_group(ec_key_st)
|
||||
if group == nil then
|
||||
return nil, "ec.set_parameters: cannot set public key without setting \"group\""
|
||||
end
|
||||
end
|
||||
|
||||
local point = C.EC_POINT_bn2point(group, pub.ctx, nil, bn_lib.bn_ctx_tmp)
|
||||
if point == nil then
|
||||
return nil, format_error("ec.set_parameters: EC_POINT_bn2point")
|
||||
end
|
||||
ffi_gc(point, C.EC_POINT_free)
|
||||
|
||||
if C.EC_KEY_set_public_key(ec_key_st, point) ~= 1 then
|
||||
return nil, format_error("ec.set_parameters: EC_KEY_set_public_key")
|
||||
end
|
||||
end
|
||||
|
||||
local priv = opts["private"]
|
||||
if priv then
|
||||
-- openssl duplicates it inside
|
||||
if C.EC_KEY_set_private_key(ec_key_st, priv.ctx) ~= 1 then
|
||||
return nil, format_error("ec.set_parameters: EC_KEY_set_private_key")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return _M
|
|
@ -0,0 +1,67 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
local ffi_str = ffi.string
|
||||
|
||||
require "resty.openssl.include.ec"
|
||||
require "resty.openssl.include.evp"
|
||||
local ctypes = require "resty.openssl.auxiliary.ctypes"
|
||||
local format_error = require("resty.openssl.err").format_error
|
||||
|
||||
local _M = {}
|
||||
|
||||
_M.params = {"public", "private"}
|
||||
|
||||
local empty_table = {}
|
||||
|
||||
local MAX_ECX_KEY_SIZE = 114 -- ed448 uses 114 bytes
|
||||
|
||||
function _M.get_parameters(evp_pkey_st)
|
||||
return setmetatable(empty_table, {
|
||||
__index = function(_, k)
|
||||
local buf = ctypes.uchar_array(MAX_ECX_KEY_SIZE)
|
||||
local length = ctypes.ptr_of_size_t(MAX_ECX_KEY_SIZE)
|
||||
|
||||
if k == 'public' or k == "pub_key" then
|
||||
if C.EVP_PKEY_get_raw_public_key(evp_pkey_st, buf, length) ~= 1 then
|
||||
error(format_error("ecx.get_parameters: EVP_PKEY_get_raw_private_key"))
|
||||
end
|
||||
elseif k == 'private' or k == "priv ~=_key" then
|
||||
if C.EVP_PKEY_get_raw_private_key(evp_pkey_st, buf, length) ~= 1 then
|
||||
return nil, format_error("ecx.get_parameters: EVP_PKEY_get_raw_private_key")
|
||||
end
|
||||
else
|
||||
return nil, "ecx.get_parameters: unknown parameter \"" .. k .. "\" for EC key"
|
||||
end
|
||||
return ffi_str(buf, length[0])
|
||||
end
|
||||
}), nil
|
||||
end
|
||||
|
||||
function _M.set_parameters(key_type, evp_pkey_st, opts)
|
||||
-- for ecx keys we always create a new EVP_PKEY and release the old one
|
||||
-- Note: we allow to pass a nil as evp_pkey_st to create a new EVP_PKEY
|
||||
local key
|
||||
if opts.private then
|
||||
local priv = opts.private
|
||||
key = C.EVP_PKEY_new_raw_private_key(key_type, nil, priv, #priv)
|
||||
if key == nil then
|
||||
return nil, format_error("ecx.set_parameters: EVP_PKEY_new_raw_private_key")
|
||||
end
|
||||
elseif opts.public then
|
||||
local pub = opts.public
|
||||
key = C.EVP_PKEY_new_raw_public_key(key_type, nil, pub, #pub)
|
||||
if key == nil then
|
||||
return nil, format_error("ecx.set_parameters: EVP_PKEY_new_raw_public_key")
|
||||
end
|
||||
else
|
||||
return nil, "no parameter is specified"
|
||||
end
|
||||
|
||||
if evp_pkey_st ~= nil then
|
||||
C.EVP_PKEY_free(evp_pkey_st)
|
||||
end
|
||||
return key
|
||||
|
||||
end
|
||||
|
||||
return _M
|
|
@ -0,0 +1,62 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
local ffi_str = ffi.string
|
||||
local ffi_sizeof = ffi.sizeof
|
||||
|
||||
local ctypes = require "resty.openssl.auxiliary.ctypes"
|
||||
require "resty.openssl.include.err"
|
||||
|
||||
local constchar_ptrptr = ffi.typeof("const char*[1]")
|
||||
|
||||
local buf = ffi.new('char[256]')
|
||||
|
||||
local function format_error(ctx, code, all_errors)
|
||||
local errors = {}
|
||||
if code then
|
||||
table.insert(errors, string.format("code: %d", code or 0))
|
||||
end
|
||||
-- get the OpenSSL errors
|
||||
while C.ERR_peek_error() ~= 0 do
|
||||
local line = ctypes.ptr_of_int()
|
||||
local path = constchar_ptrptr()
|
||||
local code
|
||||
if all_errors then
|
||||
code = C.ERR_get_error_line(path, line)
|
||||
else
|
||||
code = C.ERR_peek_last_error_line(path, line)
|
||||
end
|
||||
|
||||
local abs_path = ffi_str(path[0])
|
||||
-- ../crypto/asn1/a_d2i_fp.c => crypto/asn1/a_d2i_fp.c
|
||||
local start = abs_path:find("/")
|
||||
if start then
|
||||
abs_path = abs_path:sub(start+1)
|
||||
end
|
||||
|
||||
C.ERR_error_string_n(code, buf, ffi_sizeof(buf))
|
||||
table.insert(errors, string.format("%s:%d:%s",
|
||||
abs_path, line[0], ffi_str(buf))
|
||||
)
|
||||
|
||||
if not all_errors then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
C.ERR_clear_error()
|
||||
|
||||
if #errors > 0 then
|
||||
return string.format("%s%s%s", (ctx or ""), (ctx and ": " or ""), table.concat(errors, " "))
|
||||
else
|
||||
return string.format("%s failed", ctx)
|
||||
end
|
||||
end
|
||||
|
||||
local function format_all_error(ctx, code)
|
||||
return format_error(ctx, code, true)
|
||||
end
|
||||
|
||||
return {
|
||||
format_error = format_error,
|
||||
format_all_error = format_all_error,
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
local ffi_gc = ffi.gc
|
||||
local ffi_str = ffi.string
|
||||
|
||||
require "resty.openssl.include.hmac"
|
||||
require "resty.openssl.include.evp.md"
|
||||
local ctypes = require "resty.openssl.auxiliary.ctypes"
|
||||
local format_error = require("resty.openssl.err").format_error
|
||||
local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10
|
||||
local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER
|
||||
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X
|
||||
|
||||
local _M = {}
|
||||
local mt = {__index = _M}
|
||||
|
||||
local hmac_ctx_ptr_ct = ffi.typeof('HMAC_CTX*')
|
||||
|
||||
-- Note: https://www.openssl.org/docs/manmaster/man3/HMAC_Init.html
|
||||
-- Replace with EVP_MAC_* functions for OpenSSL 3.0
|
||||
|
||||
function _M.new(key, typ)
|
||||
local ctx
|
||||
if OPENSSL_11_OR_LATER then
|
||||
ctx = C.HMAC_CTX_new()
|
||||
ffi_gc(ctx, C.HMAC_CTX_free)
|
||||
elseif OPENSSL_10 then
|
||||
ctx = ffi.new('HMAC_CTX')
|
||||
C.HMAC_CTX_init(ctx)
|
||||
ffi_gc(ctx, C.HMAC_CTX_cleanup)
|
||||
end
|
||||
if ctx == nil then
|
||||
return nil, "hmac.new: failed to create HMAC_CTX"
|
||||
end
|
||||
|
||||
local algo = C.EVP_get_digestbyname(typ or 'sha1')
|
||||
if algo == nil then
|
||||
return nil, string.format("hmac.new: invalid digest type \"%s\"", typ)
|
||||
end
|
||||
|
||||
local code = C.HMAC_Init_ex(ctx, key, #key, algo, nil)
|
||||
if code ~= 1 then
|
||||
return nil, format_error("hmac.new")
|
||||
end
|
||||
|
||||
return setmetatable({
|
||||
ctx = ctx,
|
||||
algo = algo,
|
||||
buf = ctypes.uchar_array(OPENSSL_3X and C.EVP_MD_get_size(algo) or C.EVP_MD_size(algo)),
|
||||
}, mt), nil
|
||||
end
|
||||
|
||||
function _M.istype(l)
|
||||
return l and l.ctx and ffi.istype(hmac_ctx_ptr_ct, l.ctx)
|
||||
end
|
||||
|
||||
function _M:update(...)
|
||||
for _, s in ipairs({...}) do
|
||||
if C.HMAC_Update(self.ctx, s, #s) ~= 1 then
|
||||
return false, format_error("hmac:update")
|
||||
end
|
||||
end
|
||||
return true, nil
|
||||
end
|
||||
|
||||
local result_length = ctypes.ptr_of_uint()
|
||||
|
||||
function _M:final(s)
|
||||
if s then
|
||||
if C.HMAC_Update(self.ctx, s, #s) ~= 1 then
|
||||
return false, format_error("hmac:final")
|
||||
end
|
||||
end
|
||||
|
||||
if C.HMAC_Final(self.ctx, self.buf, result_length) ~= 1 then
|
||||
return nil, format_error("hmac:final: HMAC_Final")
|
||||
end
|
||||
return ffi_str(self.buf, result_length[0])
|
||||
end
|
||||
|
||||
function _M:reset()
|
||||
local code = C.HMAC_Init_ex(self.ctx, nil, 0, nil, nil)
|
||||
if code ~= 1 then
|
||||
return false, format_error("hmac:reset")
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return _M
|
|
@ -0,0 +1,94 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X
|
||||
|
||||
ffi.cdef [[
|
||||
typedef struct ASN1_VALUE_st ASN1_VALUE;
|
||||
|
||||
typedef struct asn1_type_st ASN1_TYPE;
|
||||
|
||||
ASN1_IA5STRING *ASN1_IA5STRING_new();
|
||||
|
||||
int ASN1_STRING_type(const ASN1_STRING *x);
|
||||
ASN1_STRING *ASN1_STRING_type_new(int type);
|
||||
int ASN1_STRING_set(ASN1_STRING *str, const void *data, int len);
|
||||
|
||||
ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai);
|
||||
BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai, BIGNUM *bn);
|
||||
|
||||
typedef int time_t;
|
||||
ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t);
|
||||
|
||||
int ASN1_INTEGER_set(ASN1_INTEGER *a, long v);
|
||||
long ASN1_INTEGER_get(const ASN1_INTEGER *a);
|
||||
int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v);
|
||||
|
||||
int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v);
|
||||
|
||||
int ASN1_STRING_length(const ASN1_STRING *x);
|
||||
]]
|
||||
|
||||
local function declare_asn1_functions(typ, has_ex)
|
||||
local t = {}
|
||||
for i=1, 7 do
|
||||
t[i] = typ
|
||||
end
|
||||
|
||||
ffi.cdef(string.format([[
|
||||
%s *%s_new(void);
|
||||
void %s_free(%s *a);
|
||||
%s *%s_dup(%s *a);
|
||||
]], unpack(t)))
|
||||
|
||||
if OPENSSL_3X and has_ex then
|
||||
ffi.cdef(string.format([[
|
||||
%s *%s_new_ex(OSSL_LIB_CTX *libctx, const char *propq);
|
||||
]], typ, typ))
|
||||
end
|
||||
end
|
||||
|
||||
declare_asn1_functions("ASN1_INTEGER")
|
||||
declare_asn1_functions("ASN1_OBJECT")
|
||||
declare_asn1_functions("ASN1_STRING")
|
||||
declare_asn1_functions("ASN1_ENUMERATED")
|
||||
|
||||
local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10
|
||||
local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER
|
||||
local BORINGSSL_110 = require("resty.openssl.version").BORINGSSL_110
|
||||
|
||||
local ASN1_STRING_get0_data
|
||||
if OPENSSL_11_OR_LATER then
|
||||
ffi.cdef[[
|
||||
const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x);
|
||||
]]
|
||||
ASN1_STRING_get0_data = C.ASN1_STRING_get0_data
|
||||
elseif OPENSSL_10 then
|
||||
ffi.cdef[[
|
||||
unsigned char *ASN1_STRING_data(ASN1_STRING *x);
|
||||
typedef struct ASN1_ENCODING_st {
|
||||
unsigned char *enc; /* DER encoding */
|
||||
long len; /* Length of encoding */
|
||||
int modified; /* set to 1 if 'enc' is invalid */
|
||||
} ASN1_ENCODING;
|
||||
]]
|
||||
ASN1_STRING_get0_data = C.ASN1_STRING_data
|
||||
end
|
||||
|
||||
if BORINGSSL_110 then
|
||||
ffi.cdef [[
|
||||
// required by resty/openssl/include/x509/crl.lua
|
||||
typedef struct ASN1_ENCODING_st {
|
||||
unsigned char *enc; /* DER encoding */
|
||||
long len; /* Length of encoding */
|
||||
int modified; /* set to 1 if 'enc' is invalid */
|
||||
} ASN1_ENCODING;
|
||||
]]
|
||||
end
|
||||
|
||||
return {
|
||||
ASN1_STRING_get0_data = ASN1_STRING_get0_data,
|
||||
declare_asn1_functions = declare_asn1_functions,
|
||||
has_new_ex = true,
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
local ffi = require "ffi"
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
|
||||
ffi.cdef [[
|
||||
typedef struct bio_method_st BIO_METHOD;
|
||||
long BIO_ctrl(BIO *bp, int cmd, long larg, void *parg);
|
||||
BIO *BIO_new_mem_buf(const void *buf, int len);
|
||||
BIO *BIO_new(const BIO_METHOD *type);
|
||||
int BIO_free(BIO *a);
|
||||
const BIO_METHOD *BIO_s_mem(void);
|
||||
int BIO_read(BIO *b, void *data, int dlen);
|
||||
]]
|
|
@ -0,0 +1,79 @@
|
|||
local ffi = require "ffi"
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X
|
||||
|
||||
local BN_ULONG
|
||||
if ffi.abi('64bit') then
|
||||
BN_ULONG = 'unsigned long long'
|
||||
else -- 32bit
|
||||
BN_ULONG = 'unsigned int'
|
||||
end
|
||||
|
||||
ffi.cdef(
|
||||
[[
|
||||
BIGNUM *BN_new(void);
|
||||
void BN_free(BIGNUM *a);
|
||||
|
||||
BN_CTX *BN_CTX_new(void);
|
||||
void BN_CTX_init(BN_CTX *c);
|
||||
void BN_CTX_free(BN_CTX *c);
|
||||
|
||||
BIGNUM *BN_dup(const BIGNUM *a);
|
||||
int BN_add_word(BIGNUM *a, ]] .. BN_ULONG ..[[ w);
|
||||
int BN_set_word(BIGNUM *a, ]] .. BN_ULONG ..[[ w);
|
||||
]] .. BN_ULONG ..[[ BN_get_word(BIGNUM *a);
|
||||
int BN_num_bits(const BIGNUM *a);
|
||||
BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
|
||||
int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen);
|
||||
|
||||
int BN_hex2bn(BIGNUM **a, const char *str);
|
||||
int BN_dec2bn(BIGNUM **a, const char *str);
|
||||
int BN_bn2bin(const BIGNUM *a, unsigned char *to);
|
||||
char *BN_bn2hex(const BIGNUM *a);
|
||||
char *BN_bn2dec(const BIGNUM *a);
|
||||
|
||||
void BN_set_negative(BIGNUM *a, int n);
|
||||
int BN_is_negative(const BIGNUM *a);
|
||||
|
||||
int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
|
||||
int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
|
||||
int BN_mul(BIGNUM *r, BIGNUM *a, BIGNUM *b, BN_CTX *ctx);
|
||||
int BN_sqr(BIGNUM *r, BIGNUM *a, BN_CTX *ctx);
|
||||
int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *a, const BIGNUM *d,
|
||||
BN_CTX *ctx);
|
||||
int BN_mod_add(BIGNUM *ret, BIGNUM *a, BIGNUM *b, const BIGNUM *m,
|
||||
BN_CTX *ctx);
|
||||
int BN_mod_sub(BIGNUM *ret, BIGNUM *a, BIGNUM *b, const BIGNUM *m,
|
||||
BN_CTX *ctx);
|
||||
int BN_mod_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, const BIGNUM *m,
|
||||
BN_CTX *ctx);
|
||||
int BN_mod_sqr(BIGNUM *ret, BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
|
||||
int BN_exp(BIGNUM *r, BIGNUM *a, BIGNUM *p, BN_CTX *ctx);
|
||||
int BN_mod_exp(BIGNUM *r, BIGNUM *a, const BIGNUM *p,
|
||||
const BIGNUM *m, BN_CTX *ctx);
|
||||
int BN_gcd(BIGNUM *r, BIGNUM *a, BIGNUM *b, BN_CTX *ctx);
|
||||
|
||||
int BN_lshift(BIGNUM *r, const BIGNUM *a, int n);
|
||||
int BN_rshift(BIGNUM *r, BIGNUM *a, int n);
|
||||
|
||||
int BN_cmp(BIGNUM *a, BIGNUM *b);
|
||||
int BN_ucmp(BIGNUM *a, BIGNUM *b);
|
||||
|
||||
// openssl >= 1.1 only
|
||||
int BN_is_zero(BIGNUM *a);
|
||||
int BN_is_one(BIGNUM *a);
|
||||
int BN_is_word(BIGNUM *a, ]] .. BN_ULONG ..[[ w);
|
||||
int BN_is_odd(BIGNUM *a);
|
||||
|
||||
int BN_is_prime_ex(const BIGNUM *p,int nchecks, BN_CTX *ctx, BN_GENCB *cb);
|
||||
int BN_generate_prime_ex(BIGNUM *ret,int bits,int safe, const BIGNUM *add,
|
||||
const BIGNUM *rem, BN_GENCB *cb);
|
||||
]]
|
||||
)
|
||||
|
||||
if OPENSSL_3X then
|
||||
ffi.cdef [[
|
||||
int BN_check_prime(const BIGNUM *p, BN_CTX *ctx, BN_GENCB *cb);
|
||||
]]
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
local ffi = require "ffi"
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
|
||||
ffi.cdef [[
|
||||
CONF *NCONF_new(CONF_METHOD *meth);
|
||||
void NCONF_free(CONF *conf);
|
||||
int NCONF_load_bio(CONF *conf, BIO *bp, long *eline);
|
||||
]]
|
|
@ -0,0 +1,31 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
|
||||
local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10
|
||||
local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER
|
||||
|
||||
local OPENSSL_free
|
||||
if OPENSSL_10 then
|
||||
ffi.cdef [[
|
||||
void CRYPTO_free(void *ptr);
|
||||
]]
|
||||
OPENSSL_free = C.CRYPTO_free
|
||||
elseif OPENSSL_11_OR_LATER then
|
||||
ffi.cdef [[
|
||||
void CRYPTO_free(void *ptr, const char *file, int line);
|
||||
]]
|
||||
OPENSSL_free = function(ptr)
|
||||
-- file and line is for debuggin only, since we can't know the c file info
|
||||
-- the macro is expanded, just ignore this
|
||||
C.CRYPTO_free(ptr, "", 0)
|
||||
end
|
||||
end
|
||||
|
||||
ffi.cdef [[
|
||||
int FIPS_mode(void);
|
||||
int FIPS_mode_set(int ONOFF);
|
||||
]]
|
||||
|
||||
return {
|
||||
OPENSSL_free = OPENSSL_free,
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
require "resty.openssl.include.objects"
|
||||
local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10
|
||||
local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER
|
||||
|
||||
if OPENSSL_11_OR_LATER then
|
||||
ffi.cdef [[
|
||||
void DH_get0_pqg(const DH *dh,
|
||||
const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
|
||||
int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g);
|
||||
void DH_get0_key(const DH *dh,
|
||||
const BIGNUM **pub_key, const BIGNUM **priv_key);
|
||||
int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key);
|
||||
]]
|
||||
elseif OPENSSL_10 then
|
||||
ffi.cdef [[
|
||||
struct dh_st {
|
||||
/*
|
||||
* This first argument is used to pick up errors when a DH is passed
|
||||
* instead of a EVP_PKEY
|
||||
*/
|
||||
int pad;
|
||||
int version;
|
||||
BIGNUM *p;
|
||||
BIGNUM *g;
|
||||
long length; /* optional */
|
||||
BIGNUM *pub_key; /* g^x */
|
||||
BIGNUM *priv_key; /* x */
|
||||
int flags;
|
||||
/*BN_MONT_CTX*/ void *method_mont_p;
|
||||
/* Place holders if we want to do X9.42 DH */
|
||||
BIGNUM *q;
|
||||
BIGNUM *j;
|
||||
unsigned char *seed;
|
||||
int seedlen;
|
||||
BIGNUM *counter;
|
||||
int references;
|
||||
/* trimmer */
|
||||
// CRYPTO_EX_DATA ex_data;
|
||||
// const DH_METHOD *meth;
|
||||
// ENGINE *engine;
|
||||
};
|
||||
]]
|
||||
end
|
||||
|
||||
ffi.cdef [[
|
||||
DH *DH_get_1024_160(void);
|
||||
DH *DH_get_2048_224(void);
|
||||
DH *DH_get_2048_256(void);
|
||||
DH *DH_new_by_nid(int nid);
|
||||
]];
|
||||
|
||||
|
||||
local dh_groups = {
|
||||
-- per https://tools.ietf.org/html/rfc5114
|
||||
dh_1024_160 = function() return C.DH_get_1024_160() end,
|
||||
dh_2048_224 = function() return C.DH_get_2048_224() end,
|
||||
dh_2048_256 = function() return C.DH_get_2048_256() end,
|
||||
}
|
||||
|
||||
local groups = {
|
||||
"ffdhe2048", "ffdhe3072", "ffdhe4096", "ffdhe6144", "ffdhe8192",
|
||||
"modp_2048", "modp_3072", "modp_4096", "modp_6144", "modp_8192",
|
||||
-- following cannot be used with FIPS provider
|
||||
"modp_1536", -- and the RFC5114 ones
|
||||
}
|
||||
|
||||
for _, group in ipairs(groups) do
|
||||
local nid = C.OBJ_sn2nid(group)
|
||||
if nid ~= 0 then
|
||||
dh_groups[group] = function() return C.DH_new_by_nid(nid) end
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
dh_groups = dh_groups,
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
local ffi = require "ffi"
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
|
||||
ffi.cdef [[
|
||||
/** Enum for the point conversion form as defined in X9.62 (ECDSA)
|
||||
* for the encoding of a elliptic curve point (x,y) */
|
||||
typedef enum {
|
||||
/** the point is encoded as z||x, where the octet z specifies
|
||||
* which solution of the quadratic equation y is */
|
||||
POINT_CONVERSION_COMPRESSED = 2,
|
||||
/** the point is encoded as z||x||y, where z is the octet 0x04 */
|
||||
POINT_CONVERSION_UNCOMPRESSED = 4,
|
||||
/** the point is encoded as z||x||y, where the octet z specifies
|
||||
* which solution of the quadratic equation y is */
|
||||
POINT_CONVERSION_HYBRID = 6
|
||||
} point_conversion_form_t;
|
||||
|
||||
EC_KEY *EC_KEY_new(void);
|
||||
void EC_KEY_free(EC_KEY *key);
|
||||
|
||||
EC_GROUP *EC_GROUP_new_by_curve_name(int nid);
|
||||
void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag);
|
||||
void EC_GROUP_set_point_conversion_form(EC_GROUP *group,
|
||||
point_conversion_form_t form);
|
||||
void EC_GROUP_set_curve_name(EC_GROUP *group, int nid);
|
||||
int EC_GROUP_get_curve_name(const EC_GROUP *group);
|
||||
|
||||
|
||||
void EC_GROUP_free(EC_GROUP *group);
|
||||
|
||||
BIGNUM *EC_POINT_point2bn(const EC_GROUP *, const EC_POINT *,
|
||||
point_conversion_form_t form, BIGNUM *, BN_CTX *);
|
||||
// for BoringSSL
|
||||
size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *p,
|
||||
point_conversion_form_t form,
|
||||
unsigned char *buf, size_t len, BN_CTX *ctx);
|
||||
// OpenSSL < 1.1.1
|
||||
int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group,
|
||||
const EC_POINT *p,
|
||||
BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
|
||||
// OpenSSL >= 1.1.1
|
||||
int EC_POINT_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *p,
|
||||
BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
|
||||
EC_POINT *EC_POINT_bn2point(const EC_GROUP *group, const BIGNUM *bn,
|
||||
EC_POINT *p, BN_CTX *ctx);
|
||||
|
||||
point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key);
|
||||
|
||||
const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key);
|
||||
int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *prv);
|
||||
|
||||
const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key);
|
||||
int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub);
|
||||
int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, BIGNUM *y);
|
||||
|
||||
const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key);
|
||||
int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group);
|
||||
]]
|
|
@ -0,0 +1,16 @@
|
|||
local ffi = require "ffi"
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
|
||||
ffi.cdef [[
|
||||
ECDSA_SIG *ECDSA_SIG_new(void);
|
||||
void ECDSA_SIG_free(ECDSA_SIG *sig);
|
||||
|
||||
void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
|
||||
int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s);
|
||||
|
||||
int i2d_ECDSA_SIG(const ECDSA_SIG *sig, unsigned char **pp);
|
||||
ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **sig, const unsigned char **pp, long len);
|
||||
|
||||
int EC_GROUP_order_bits(const EC_GROUP *group);
|
||||
]]
|
|
@ -0,0 +1,9 @@
|
|||
local ffi = require "ffi"
|
||||
|
||||
ffi.cdef [[
|
||||
unsigned long ERR_peek_error(void);
|
||||
unsigned long ERR_peek_last_error_line(const char **file, int *line);
|
||||
unsigned long ERR_get_error_line(const char **file, int *line);
|
||||
void ERR_clear_error(void);
|
||||
void ERR_error_string_n(unsigned long e, char *buf, size_t len);
|
||||
]]
|
|
@ -0,0 +1,109 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
local bit = require("bit")
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
require "resty.openssl.include.err"
|
||||
require "resty.openssl.include.objects"
|
||||
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X
|
||||
local BORINGSSL = require("resty.openssl.version").BORINGSSL
|
||||
|
||||
if BORINGSSL then
|
||||
ffi.cdef [[
|
||||
int PKCS5_PBKDF2_HMAC(const char *password, size_t password_len,
|
||||
const uint8_t *salt, size_t salt_len,
|
||||
unsigned iterations, const EVP_MD *digest,
|
||||
size_t key_len, uint8_t *out_key);
|
||||
int EVP_PBE_scrypt(const char *password, size_t password_len,
|
||||
const uint8_t *salt, size_t salt_len,
|
||||
uint64_t N, uint64_t r, uint64_t p,
|
||||
size_t max_mem, uint8_t *out_key,
|
||||
size_t key_len);
|
||||
]]
|
||||
else
|
||||
ffi.cdef [[
|
||||
/* KDF */
|
||||
int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
|
||||
const unsigned char *salt, int saltlen, int iter,
|
||||
const EVP_MD *digest, int keylen, unsigned char *out);
|
||||
|
||||
int EVP_PBE_scrypt(const char *pass, size_t passlen,
|
||||
const unsigned char *salt, size_t saltlen,
|
||||
uint64_t N, uint64_t r, uint64_t p, uint64_t maxmem,
|
||||
unsigned char *key, size_t keylen);
|
||||
]]
|
||||
end
|
||||
|
||||
if OPENSSL_3X then
|
||||
require "resty.openssl.include.provider"
|
||||
|
||||
ffi.cdef [[
|
||||
int EVP_set_default_properties(OSSL_LIB_CTX *libctx, const char *propq);
|
||||
int EVP_default_properties_enable_fips(OSSL_LIB_CTX *libctx, int enable);
|
||||
int EVP_default_properties_is_fips_enabled(OSSL_LIB_CTX *libctx);
|
||||
|
||||
// const OSSL_PROVIDER *EVP_RAND_get0_provider(const EVP_RAND *rand);
|
||||
// EVP_RAND *EVP_RAND_fetch(OSSL_LIB_CTX *libctx, const char *algorithm,
|
||||
// const char *properties);
|
||||
]]
|
||||
end
|
||||
|
||||
local EVP_PKEY_ALG_CTRL = 0x1000
|
||||
|
||||
local _M = {
|
||||
EVP_PKEY_RSA = C.OBJ_txt2nid("rsaEncryption"),
|
||||
EVP_PKEY_DH = C.OBJ_txt2nid("dhKeyAgreement"),
|
||||
EVP_PKEY_EC = C.OBJ_txt2nid("id-ecPublicKey"),
|
||||
EVP_PKEY_X25519 = C.OBJ_txt2nid("X25519"),
|
||||
EVP_PKEY_ED25519 = C.OBJ_txt2nid("ED25519"),
|
||||
EVP_PKEY_X448 = C.OBJ_txt2nid("X448"),
|
||||
EVP_PKEY_ED448 = C.OBJ_txt2nid("ED448"),
|
||||
|
||||
EVP_PKEY_OP_PARAMGEN = bit.lshift(1, 1),
|
||||
EVP_PKEY_OP_KEYGEN = bit.lshift(1, 2),
|
||||
EVP_PKEY_OP_SIGN = bit.lshift(1, 3),
|
||||
EVP_PKEY_OP_VERIFY = bit.lshift(1, 4),
|
||||
EVP_PKEY_OP_DERIVE = OPENSSL_3X and bit.lshift(1, 12) or bit.lshift(1, 10),
|
||||
|
||||
EVP_PKEY_ALG_CTRL = EVP_PKEY_ALG_CTRL,
|
||||
|
||||
|
||||
EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN = EVP_PKEY_ALG_CTRL + 1,
|
||||
EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID = EVP_PKEY_ALG_CTRL + 1,
|
||||
EVP_PKEY_CTRL_EC_PARAM_ENC = EVP_PKEY_ALG_CTRL + 2,
|
||||
EVP_PKEY_CTRL_RSA_KEYGEN_BITS = EVP_PKEY_ALG_CTRL + 3,
|
||||
EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP = EVP_PKEY_ALG_CTRL + 4,
|
||||
EVP_PKEY_CTRL_RSA_PADDING = EVP_PKEY_ALG_CTRL + 1,
|
||||
EVP_PKEY_CTRL_RSA_PSS_SALTLEN = EVP_PKEY_ALG_CTRL + 2,
|
||||
|
||||
EVP_CTRL_AEAD_SET_IVLEN = 0x9,
|
||||
EVP_CTRL_AEAD_GET_TAG = 0x10,
|
||||
EVP_CTRL_AEAD_SET_TAG = 0x11,
|
||||
|
||||
EVP_PKEY_CTRL_TLS_MD = EVP_PKEY_ALG_CTRL,
|
||||
EVP_PKEY_CTRL_TLS_SECRET = EVP_PKEY_ALG_CTRL + 1,
|
||||
EVP_PKEY_CTRL_TLS_SEED = EVP_PKEY_ALG_CTRL + 2,
|
||||
EVP_PKEY_CTRL_HKDF_MD = EVP_PKEY_ALG_CTRL + 3,
|
||||
EVP_PKEY_CTRL_HKDF_SALT = EVP_PKEY_ALG_CTRL + 4,
|
||||
EVP_PKEY_CTRL_HKDF_KEY = EVP_PKEY_ALG_CTRL + 5,
|
||||
EVP_PKEY_CTRL_HKDF_INFO = EVP_PKEY_ALG_CTRL + 6,
|
||||
EVP_PKEY_CTRL_HKDF_MODE = EVP_PKEY_ALG_CTRL + 7,
|
||||
EVP_PKEY_CTRL_PASS = EVP_PKEY_ALG_CTRL + 8,
|
||||
EVP_PKEY_CTRL_SCRYPT_SALT = EVP_PKEY_ALG_CTRL + 9,
|
||||
EVP_PKEY_CTRL_SCRYPT_N = EVP_PKEY_ALG_CTRL + 10,
|
||||
EVP_PKEY_CTRL_SCRYPT_R = EVP_PKEY_ALG_CTRL + 11,
|
||||
EVP_PKEY_CTRL_SCRYPT_P = EVP_PKEY_ALG_CTRL + 12,
|
||||
EVP_PKEY_CTRL_SCRYPT_MAXMEM_BYTES = EVP_PKEY_ALG_CTRL + 13,
|
||||
}
|
||||
|
||||
-- clean up error occurs during OBJ_txt2*
|
||||
C.ERR_clear_error()
|
||||
|
||||
_M.ecx_curves = {
|
||||
Ed25519 = _M.EVP_PKEY_ED25519,
|
||||
X25519 = _M.EVP_PKEY_X25519,
|
||||
Ed448 = _M.EVP_PKEY_ED448,
|
||||
X448 = _M.EVP_PKEY_X448,
|
||||
}
|
||||
|
||||
return _M
|
|
@ -0,0 +1,123 @@
|
|||
local ffi = require "ffi"
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10
|
||||
local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER
|
||||
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X
|
||||
local BORINGSSL = require("resty.openssl.version").BORINGSSL
|
||||
|
||||
ffi.cdef [[
|
||||
// openssl < 3.0
|
||||
int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx);
|
||||
int EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx);
|
||||
int EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx);
|
||||
int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *c, int pad);
|
||||
|
||||
const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *ctx);
|
||||
const EVP_CIPHER *EVP_get_cipherbyname(const char *name);
|
||||
int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr);
|
||||
int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
int *outl, const unsigned char *in, int inl);
|
||||
int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
int *outl, const unsigned char *in, int inl);
|
||||
|
||||
|
||||
int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx,
|
||||
const EVP_CIPHER *cipher, ENGINE *impl,
|
||||
const unsigned char *key,
|
||||
const unsigned char *iv, int enc);
|
||||
int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
int *outl, const unsigned char *in, int inl);
|
||||
int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm,
|
||||
int *outl);
|
||||
|
||||
// list functions
|
||||
typedef void* fake_openssl_cipher_list_fn(const EVP_CIPHER *ciph, const char *from,
|
||||
const char *to, void *x);
|
||||
//void EVP_CIPHER_do_all_sorted(fake_openssl_cipher_list_fn*, void *arg);
|
||||
void EVP_CIPHER_do_all_sorted(void (*fn)
|
||||
(const EVP_CIPHER *ciph, const char *from,
|
||||
const char *to, void *x), void *arg);
|
||||
int EVP_CIPHER_nid(const EVP_CIPHER *cipher);
|
||||
]]
|
||||
|
||||
if BORINGSSL then
|
||||
ffi.cdef [[
|
||||
int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md,
|
||||
const uint8_t *salt, const uint8_t *data,
|
||||
size_t data_len, unsigned count, uint8_t *key,
|
||||
uint8_t *iv);
|
||||
]]
|
||||
else
|
||||
ffi.cdef [[
|
||||
int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md,
|
||||
const unsigned char *salt,
|
||||
const unsigned char *data, int datal, int count,
|
||||
unsigned char *key, unsigned char *iv);
|
||||
]]
|
||||
end
|
||||
|
||||
if OPENSSL_3X then
|
||||
require "resty.openssl.include.provider"
|
||||
|
||||
ffi.cdef [[
|
||||
int EVP_CIPHER_CTX_get_block_size(const EVP_CIPHER_CTX *ctx);
|
||||
int EVP_CIPHER_CTX_get_key_length(const EVP_CIPHER_CTX *ctx);
|
||||
int EVP_CIPHER_CTX_get_iv_length(const EVP_CIPHER_CTX *ctx);
|
||||
|
||||
int EVP_CIPHER_get_nid(const EVP_CIPHER *cipher);
|
||||
|
||||
const OSSL_PROVIDER *EVP_CIPHER_get0_provider(const EVP_CIPHER *cipher);
|
||||
EVP_CIPHER *EVP_CIPHER_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
|
||||
const char *properties);
|
||||
|
||||
typedef void* fake_openssl_cipher_provided_list_fn(EVP_CIPHER *cipher, void *arg);
|
||||
void EVP_CIPHER_do_all_provided(OSSL_LIB_CTX *libctx,
|
||||
fake_openssl_cipher_provided_list_fn*,
|
||||
void *arg);
|
||||
int EVP_CIPHER_up_ref(EVP_CIPHER *cipher);
|
||||
void EVP_CIPHER_free(EVP_CIPHER *cipher);
|
||||
|
||||
const char *EVP_CIPHER_get0_name(const EVP_CIPHER *cipher);
|
||||
|
||||
int EVP_CIPHER_CTX_set_params(EVP_CIPHER_CTX *ctx, const OSSL_PARAM params[]);
|
||||
const OSSL_PARAM *EVP_CIPHER_CTX_settable_params(EVP_CIPHER_CTX *ctx);
|
||||
int EVP_CIPHER_CTX_get_params(EVP_CIPHER_CTX *ctx, OSSL_PARAM params[]);
|
||||
const OSSL_PARAM *EVP_CIPHER_CTX_gettable_params(EVP_CIPHER_CTX *ctx);
|
||||
]]
|
||||
end
|
||||
|
||||
if OPENSSL_11_OR_LATER then
|
||||
ffi.cdef [[
|
||||
EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void);
|
||||
int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *c);
|
||||
void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *c);
|
||||
]]
|
||||
elseif OPENSSL_10 then
|
||||
ffi.cdef [[
|
||||
void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *a);
|
||||
int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *a);
|
||||
|
||||
// # define EVP_MAX_IV_LENGTH 16
|
||||
// # define EVP_MAX_BLOCK_LENGTH 32
|
||||
|
||||
struct evp_cipher_ctx_st {
|
||||
const EVP_CIPHER *cipher;
|
||||
ENGINE *engine; /* functional reference if 'cipher' is
|
||||
* ENGINE-provided */
|
||||
int encrypt; /* encrypt or decrypt */
|
||||
int buf_len; /* number we have left */
|
||||
unsigned char oiv[16]; /* original iv EVP_MAX_IV_LENGTH */
|
||||
unsigned char iv[16]; /* working iv EVP_MAX_IV_LENGTH */
|
||||
unsigned char buf[32]; /* saved partial block EVP_MAX_BLOCK_LENGTH */
|
||||
int num; /* used by cfb/ofb/ctr mode */
|
||||
void *app_data; /* application stuff */
|
||||
int key_len; /* May change for variable length cipher */
|
||||
unsigned long flags; /* Various flags */
|
||||
void *cipher_data; /* per EVP data */
|
||||
int final_used;
|
||||
int block_mask;
|
||||
unsigned char final[32]; /* possible final block EVP_MAX_BLOCK_LENGTH */
|
||||
} /* EVP_CIPHER_CTX */ ;
|
||||
]]
|
||||
end
|
|
@ -0,0 +1,148 @@
|
|||
local ffi = require "ffi"
|
||||
local ffi_cast = ffi.cast
|
||||
local C = ffi.C
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
require "resty.openssl.include.evp.md"
|
||||
local evp = require("resty.openssl.include.evp")
|
||||
local ctypes = require "resty.openssl.auxiliary.ctypes"
|
||||
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X
|
||||
local BORINGSSL = require("resty.openssl.version").BORINGSSL
|
||||
|
||||
local void_ptr = ctypes.void_ptr
|
||||
|
||||
local _M = {
|
||||
EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND = 0,
|
||||
EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY = 1,
|
||||
EVP_PKEY_HKDEF_MODE_EXPAND_ONLY = 2,
|
||||
}
|
||||
|
||||
if OPENSSL_3X then
|
||||
require "resty.openssl.include.provider"
|
||||
|
||||
ffi.cdef [[
|
||||
const OSSL_PROVIDER *EVP_KDF_get0_provider(const EVP_KDF *kdf);
|
||||
|
||||
typedef void* fake_openssl_kdf_provided_list_fn(EVP_KDF *kdf, void *arg);
|
||||
void EVP_KDF_do_all_provided(OSSL_LIB_CTX *libctx,
|
||||
fake_openssl_kdf_provided_list_fn*,
|
||||
void *arg);
|
||||
int EVP_KDF_up_ref(EVP_KDF *kdf);
|
||||
void EVP_KDF_free(EVP_KDF *kdf);
|
||||
|
||||
const char *EVP_KDF_get0_name(const EVP_KDF *kdf);
|
||||
|
||||
EVP_KDF *EVP_KDF_fetch(OSSL_LIB_CTX *libctx, const char *algorithm,
|
||||
const char *properties);
|
||||
EVP_KDF_CTX *EVP_KDF_CTX_new(const EVP_KDF *kdf);
|
||||
void EVP_KDF_CTX_free(EVP_KDF_CTX *ctx);
|
||||
void EVP_KDF_CTX_reset(EVP_KDF_CTX *ctx);
|
||||
|
||||
size_t EVP_KDF_CTX_get_kdf_size(EVP_KDF_CTX *ctx);
|
||||
int EVP_KDF_derive(EVP_KDF_CTX *ctx, unsigned char *key, size_t keylen,
|
||||
const OSSL_PARAM params[]);
|
||||
|
||||
int EVP_KDF_CTX_get_params(EVP_KDF_CTX *ctx, OSSL_PARAM params[]);
|
||||
int EVP_KDF_CTX_set_params(EVP_KDF_CTX *ctx, const OSSL_PARAM params[]);
|
||||
const OSSL_PARAM *EVP_KDF_CTX_gettable_params(const EVP_KDF_CTX *ctx);
|
||||
const OSSL_PARAM *EVP_KDF_CTX_settable_params(const EVP_KDF_CTX *ctx);
|
||||
]]
|
||||
end
|
||||
|
||||
if OPENSSL_3X or BORINGSSL then
|
||||
ffi.cdef [[
|
||||
int EVP_PKEY_CTX_set_tls1_prf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
|
||||
int EVP_PKEY_CTX_set1_tls1_prf_secret(EVP_PKEY_CTX *pctx,
|
||||
const unsigned char *sec, int seclen);
|
||||
int EVP_PKEY_CTX_add1_tls1_prf_seed(EVP_PKEY_CTX *pctx,
|
||||
const unsigned char *seed, int seedlen);
|
||||
|
||||
int EVP_PKEY_CTX_set_hkdf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
|
||||
int EVP_PKEY_CTX_set1_hkdf_salt(EVP_PKEY_CTX *ctx,
|
||||
const unsigned char *salt, int saltlen);
|
||||
int EVP_PKEY_CTX_set1_hkdf_key(EVP_PKEY_CTX *ctx,
|
||||
const unsigned char *key, int keylen);
|
||||
int EVP_PKEY_CTX_set_hkdf_mode(EVP_PKEY_CTX *ctx, int mode);
|
||||
int EVP_PKEY_CTX_add1_hkdf_info(EVP_PKEY_CTX *ctx,
|
||||
const unsigned char *info, int infolen);
|
||||
]]
|
||||
|
||||
_M.EVP_PKEY_CTX_set_tls1_prf_md = function(pctx, md)
|
||||
return C.EVP_PKEY_CTX_set_tls1_prf_md(pctx, md)
|
||||
end
|
||||
_M.EVP_PKEY_CTX_set1_tls1_prf_secret = function(pctx, sec)
|
||||
return C.EVP_PKEY_CTX_set1_tls1_prf_secret(pctx, sec, #sec)
|
||||
end
|
||||
_M.EVP_PKEY_CTX_add1_tls1_prf_seed = function(pctx, seed)
|
||||
return C.EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, seed, #seed)
|
||||
end
|
||||
|
||||
_M.EVP_PKEY_CTX_set_hkdf_md = function(pctx, md)
|
||||
return C.EVP_PKEY_CTX_set_hkdf_md(pctx, md)
|
||||
end
|
||||
_M.EVP_PKEY_CTX_set1_hkdf_salt = function(pctx, salt)
|
||||
return C.EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, #salt)
|
||||
end
|
||||
_M.EVP_PKEY_CTX_set1_hkdf_key = function(pctx, key)
|
||||
return C.EVP_PKEY_CTX_set1_hkdf_key(pctx, key, #key)
|
||||
end
|
||||
_M.EVP_PKEY_CTX_set_hkdf_mode = function(pctx, mode)
|
||||
return C.EVP_PKEY_CTX_set_hkdf_mode(pctx, mode)
|
||||
end
|
||||
_M.EVP_PKEY_CTX_add1_hkdf_info = function(pctx, info)
|
||||
return C.EVP_PKEY_CTX_add1_hkdf_info(pctx, info, #info)
|
||||
end
|
||||
|
||||
else
|
||||
_M.EVP_PKEY_CTX_set_tls1_prf_md = function(pctx, md)
|
||||
return C.EVP_PKEY_CTX_ctrl(pctx, -1,
|
||||
evp.EVP_PKEY_OP_DERIVE,
|
||||
evp.EVP_PKEY_CTRL_TLS_MD,
|
||||
0, ffi_cast(void_ptr, md))
|
||||
end
|
||||
_M.EVP_PKEY_CTX_set1_tls1_prf_secret = function(pctx, sec)
|
||||
return C.EVP_PKEY_CTX_ctrl(pctx, -1,
|
||||
evp.EVP_PKEY_OP_DERIVE,
|
||||
evp.EVP_PKEY_CTRL_TLS_SECRET,
|
||||
#sec, ffi_cast(void_ptr, sec))
|
||||
end
|
||||
_M.EVP_PKEY_CTX_add1_tls1_prf_seed = function(pctx, seed)
|
||||
return C.EVP_PKEY_CTX_ctrl(pctx, -1,
|
||||
evp.EVP_PKEY_OP_DERIVE,
|
||||
evp.EVP_PKEY_CTRL_TLS_SEED,
|
||||
#seed, ffi_cast(void_ptr, seed))
|
||||
end
|
||||
|
||||
_M.EVP_PKEY_CTX_set_hkdf_md = function(pctx, md)
|
||||
return C.EVP_PKEY_CTX_ctrl(pctx, -1,
|
||||
evp.EVP_PKEY_OP_DERIVE,
|
||||
evp.EVP_PKEY_CTRL_HKDF_MD,
|
||||
0, ffi_cast(void_ptr, md))
|
||||
end
|
||||
_M.EVP_PKEY_CTX_set1_hkdf_salt = function(pctx, salt)
|
||||
return C.EVP_PKEY_CTX_ctrl(pctx, -1,
|
||||
evp.EVP_PKEY_OP_DERIVE,
|
||||
evp.EVP_PKEY_CTRL_HKDF_SALT,
|
||||
#salt, ffi_cast(void_ptr, salt))
|
||||
end
|
||||
_M.EVP_PKEY_CTX_set1_hkdf_key = function(pctx, key)
|
||||
return C.EVP_PKEY_CTX_ctrl(pctx, -1,
|
||||
evp.EVP_PKEY_OP_DERIVE,
|
||||
evp.EVP_PKEY_CTRL_HKDF_KEY,
|
||||
#key, ffi_cast(void_ptr, key))
|
||||
end
|
||||
_M.EVP_PKEY_CTX_set_hkdf_mode = function(pctx, mode)
|
||||
return C.EVP_PKEY_CTX_ctrl(pctx, -1,
|
||||
evp.EVP_PKEY_OP_DERIVE,
|
||||
evp.EVP_PKEY_CTRL_HKDF_MODE,
|
||||
mode, nil)
|
||||
end
|
||||
_M.EVP_PKEY_CTX_add1_hkdf_info = function(pctx, info)
|
||||
return C.EVP_PKEY_CTX_ctrl(pctx, -1,
|
||||
evp.EVP_PKEY_OP_DERIVE,
|
||||
evp.EVP_PKEY_CTRL_HKDF_INFO,
|
||||
#info, ffi_cast(void_ptr, info))
|
||||
end
|
||||
end
|
||||
|
||||
return _M
|
|
@ -0,0 +1,38 @@
|
|||
local ffi = require "ffi"
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
require "resty.openssl.include.provider"
|
||||
|
||||
ffi.cdef [[
|
||||
typedef struct evp_mac_st EVP_MAC;
|
||||
typedef struct evp_mac_ctx_st EVP_MAC_CTX;
|
||||
|
||||
EVP_MAC_CTX *EVP_MAC_CTX_new(EVP_MAC *mac);
|
||||
void EVP_MAC_CTX_free(EVP_MAC_CTX *ctx);
|
||||
|
||||
const OSSL_PROVIDER *EVP_MAC_get0_provider(const EVP_MAC *mac);
|
||||
EVP_MAC *EVP_MAC_fetch(OSSL_LIB_CTX *libctx, const char *algorithm,
|
||||
const char *properties);
|
||||
|
||||
int EVP_MAC_init(EVP_MAC_CTX *ctx, const unsigned char *key, size_t keylen,
|
||||
const OSSL_PARAM params[]);
|
||||
int EVP_MAC_update(EVP_MAC_CTX *ctx, const unsigned char *data, size_t datalen);
|
||||
int EVP_MAC_final(EVP_MAC_CTX *ctx,
|
||||
unsigned char *out, size_t *outl, size_t outsize);
|
||||
|
||||
size_t EVP_MAC_CTX_get_mac_size(EVP_MAC_CTX *ctx);
|
||||
|
||||
typedef void* fake_openssl_mac_provided_list_fn(EVP_MAC *mac, void *arg);
|
||||
void EVP_MAC_do_all_provided(OSSL_LIB_CTX *libctx,
|
||||
fake_openssl_mac_provided_list_fn*,
|
||||
void *arg);
|
||||
int EVP_MAC_up_ref(EVP_MAC *mac);
|
||||
void EVP_MAC_free(EVP_MAC *mac);
|
||||
|
||||
const char *EVP_MAC_get0_name(const EVP_MAC *mac);
|
||||
|
||||
int EVP_MAC_CTX_set_params(EVP_MAC_CTX *ctx, const OSSL_PARAM params[]);
|
||||
const OSSL_PARAM *EVP_MAC_CTX_settable_params(EVP_MAC_CTX *ctx);
|
||||
int EVP_MAC_CTX_get_params(EVP_MAC_CTX *ctx, OSSL_PARAM params[]);
|
||||
const OSSL_PARAM *EVP_MAC_CTX_gettable_params(EVP_MAC_CTX *ctx);
|
||||
]]
|
|
@ -0,0 +1,86 @@
|
|||
local ffi = require "ffi"
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10
|
||||
local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER
|
||||
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X
|
||||
|
||||
ffi.cdef [[
|
||||
int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type,
|
||||
ENGINE *impl);
|
||||
int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d,
|
||||
size_t cnt);
|
||||
int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md,
|
||||
unsigned int *s);
|
||||
const EVP_MD *EVP_get_digestbyname(const char *name);
|
||||
int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d,
|
||||
size_t cnt);
|
||||
int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md,
|
||||
unsigned int *s);
|
||||
|
||||
const EVP_MD *EVP_md_null(void);
|
||||
// openssl < 3.0
|
||||
int EVP_MD_size(const EVP_MD *md);
|
||||
int EVP_MD_type(const EVP_MD *md);
|
||||
|
||||
typedef void* fake_openssl_md_list_fn(const EVP_MD *ciph, const char *from,
|
||||
const char *to, void *x);
|
||||
void EVP_MD_do_all_sorted(fake_openssl_md_list_fn*, void *arg);
|
||||
|
||||
const EVP_MD *EVP_get_digestbyname(const char *name);
|
||||
]]
|
||||
|
||||
if OPENSSL_3X then
|
||||
require "resty.openssl.include.provider"
|
||||
|
||||
ffi.cdef [[
|
||||
int EVP_MD_get_size(const EVP_MD *md);
|
||||
int EVP_MD_get_type(const EVP_MD *md);
|
||||
const OSSL_PROVIDER *EVP_MD_get0_provider(const EVP_MD *md);
|
||||
|
||||
EVP_MD *EVP_MD_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
|
||||
const char *properties);
|
||||
|
||||
typedef void* fake_openssl_md_provided_list_fn(EVP_MD *md, void *arg);
|
||||
void EVP_MD_do_all_provided(OSSL_LIB_CTX *libctx,
|
||||
fake_openssl_md_provided_list_fn*,
|
||||
void *arg);
|
||||
int EVP_MD_up_ref(EVP_MD *md);
|
||||
void EVP_MD_free(EVP_MD *md);
|
||||
|
||||
const char *EVP_MD_get0_name(const EVP_MD *md);
|
||||
|
||||
int EVP_MD_CTX_set_params(EVP_MD_CTX *ctx, const OSSL_PARAM params[]);
|
||||
const OSSL_PARAM *EVP_MD_CTX_settable_params(EVP_MD_CTX *ctx);
|
||||
int EVP_MD_CTX_get_params(EVP_MD_CTX *ctx, OSSL_PARAM params[]);
|
||||
const OSSL_PARAM *EVP_MD_CTX_gettable_params(EVP_MD_CTX *ctx);
|
||||
]]
|
||||
end
|
||||
|
||||
if OPENSSL_11_OR_LATER then
|
||||
ffi.cdef [[
|
||||
EVP_MD_CTX *EVP_MD_CTX_new(void);
|
||||
void EVP_MD_CTX_free(EVP_MD_CTX *ctx);
|
||||
]]
|
||||
elseif OPENSSL_10 then
|
||||
ffi.cdef [[
|
||||
EVP_MD_CTX *EVP_MD_CTX_create(void);
|
||||
void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx);
|
||||
|
||||
// crypto/evp/evp.h
|
||||
// only needed for openssl 1.0.x where initializer for HMAC_CTX is not avaiable
|
||||
// HACK: renamed from env_md_ctx_st to evp_md_ctx_st to match typedef (lazily)
|
||||
// it's an internal struct thus name is not exported so we will be fine
|
||||
struct evp_md_ctx_st {
|
||||
const EVP_MD *digest;
|
||||
ENGINE *engine; /* functional reference if 'digest' is
|
||||
* ENGINE-provided */
|
||||
unsigned long flags;
|
||||
void *md_data;
|
||||
/* Public key context for sign/verify */
|
||||
EVP_PKEY_CTX *pctx;
|
||||
/* Update function: usually copied from EVP_MD */
|
||||
int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count);
|
||||
} /* EVP_MD_CTX */ ;
|
||||
]]
|
||||
end
|
|
@ -0,0 +1,234 @@
|
|||
local ffi = require "ffi"
|
||||
local C = ffi.C
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
require "resty.openssl.include.evp.md"
|
||||
local evp = require("resty.openssl.include.evp")
|
||||
local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10
|
||||
local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X
|
||||
local BORINGSSL = require("resty.openssl.version").BORINGSSL
|
||||
|
||||
ffi.cdef [[
|
||||
EVP_PKEY *EVP_PKEY_new(void);
|
||||
void EVP_PKEY_free(EVP_PKEY *pkey);
|
||||
|
||||
RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey);
|
||||
EC_KEY *EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey);
|
||||
DH *EVP_PKEY_get0_DH(EVP_PKEY *pkey);
|
||||
|
||||
int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key);
|
||||
// openssl < 3.0
|
||||
int EVP_PKEY_base_id(const EVP_PKEY *pkey);
|
||||
int EVP_PKEY_size(const EVP_PKEY *pkey);
|
||||
|
||||
EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);
|
||||
EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e);
|
||||
void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx);
|
||||
int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
|
||||
int cmd, int p1, void *p2);
|
||||
// TODO replace EVP_PKEY_CTX_ctrl with EVP_PKEY_CTX_ctrl_str to reduce
|
||||
// some hardcoded macros
|
||||
int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
|
||||
const char *value);
|
||||
int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx);
|
||||
int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx,
|
||||
unsigned char *out, size_t *outlen,
|
||||
const unsigned char *in, size_t inlen);
|
||||
int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx);
|
||||
int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx,
|
||||
unsigned char *out, size_t *outlen,
|
||||
const unsigned char *in, size_t inlen);
|
||||
|
||||
int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx);
|
||||
int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
|
||||
unsigned char *sig, size_t *siglen,
|
||||
const unsigned char *tbs, size_t tbslen);
|
||||
int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx);
|
||||
int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx,
|
||||
unsigned char *rout, size_t *routlen,
|
||||
const unsigned char *sig, size_t siglen);
|
||||
|
||||
EVP_PKEY *EVP_PKEY_new_raw_private_key(int type, ENGINE *e,
|
||||
const unsigned char *key, size_t keylen);
|
||||
EVP_PKEY *EVP_PKEY_new_raw_public_key(int type, ENGINE *e,
|
||||
const unsigned char *key, size_t keylen);
|
||||
|
||||
int EVP_PKEY_get_raw_private_key(const EVP_PKEY *pkey, unsigned char *priv,
|
||||
size_t *len);
|
||||
int EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub,
|
||||
size_t *len);
|
||||
|
||||
int EVP_SignFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s,
|
||||
EVP_PKEY *pkey);
|
||||
int EVP_VerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sigbuf,
|
||||
unsigned int siglen, EVP_PKEY *pkey);
|
||||
|
||||
int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
|
||||
const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey);
|
||||
int EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret,
|
||||
size_t *siglen, const unsigned char *tbs,
|
||||
size_t tbslen);
|
||||
int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
|
||||
const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey);
|
||||
int EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret,
|
||||
size_t siglen, const unsigned char *tbs, size_t tbslen);
|
||||
|
||||
int EVP_PKEY_get_default_digest_nid(EVP_PKEY *pkey, int *pnid);
|
||||
|
||||
int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx);
|
||||
int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer);
|
||||
int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen);
|
||||
|
||||
int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx);
|
||||
int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
|
||||
int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx);
|
||||
int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
|
||||
]]
|
||||
|
||||
if OPENSSL_3X then
|
||||
require "resty.openssl.include.provider"
|
||||
|
||||
ffi.cdef [[
|
||||
int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int pad_mode);
|
||||
|
||||
int EVP_PKEY_get_base_id(const EVP_PKEY *pkey);
|
||||
int EVP_PKEY_get_size(const EVP_PKEY *pkey);
|
||||
|
||||
const OSSL_PROVIDER *EVP_PKEY_get0_provider(const EVP_PKEY *key);
|
||||
const OSSL_PROVIDER *EVP_PKEY_CTX_get0_provider(const EVP_PKEY_CTX *ctx);
|
||||
|
||||
const OSSL_PARAM *EVP_PKEY_settable_params(const EVP_PKEY *pkey);
|
||||
int EVP_PKEY_set_params(EVP_PKEY *pkey, OSSL_PARAM params[]);
|
||||
int EVP_PKEY_get_params(EVP_PKEY *ctx, OSSL_PARAM params[]);
|
||||
const OSSL_PARAM *EVP_PKEY_gettable_params(EVP_PKEY *ctx);
|
||||
]]
|
||||
end
|
||||
|
||||
if OPENSSL_10 then
|
||||
ffi.cdef [[
|
||||
// crypto/evp/evp.h
|
||||
// only needed for openssl 1.0.x where getters are not available
|
||||
// needed to get key to extract parameters
|
||||
// Note: this struct is trimmed
|
||||
struct evp_pkey_st {
|
||||
int type;
|
||||
int save_type;
|
||||
const EVP_PKEY_ASN1_METHOD *ameth;
|
||||
ENGINE *engine;
|
||||
ENGINE *pmeth_engine;
|
||||
union {
|
||||
void *ptr;
|
||||
struct rsa_st *rsa;
|
||||
struct dsa_st *dsa;
|
||||
struct dh_st *dh;
|
||||
struct ec_key_st *ec;
|
||||
} pkey;
|
||||
// trimmed
|
||||
|
||||
// CRYPTO_REF_COUNT references;
|
||||
// CRYPTO_RWLOCK *lock;
|
||||
// STACK_OF(X509_ATTRIBUTE) *attributes;
|
||||
// int save_parameters;
|
||||
|
||||
// struct {
|
||||
// EVP_KEYMGMT *keymgmt;
|
||||
// void *provkey;
|
||||
// } pkeys[10];
|
||||
// size_t dirty_cnt_copy;
|
||||
};
|
||||
]]
|
||||
end
|
||||
|
||||
local _M = {}
|
||||
|
||||
if OPENSSL_3X or BORINGSSL then
|
||||
ffi.cdef [[
|
||||
int EVP_PKEY_CTX_set_ec_paramgen_curve_nid(EVP_PKEY_CTX *ctx, int nid);
|
||||
int EVP_PKEY_CTX_set_ec_param_enc(EVP_PKEY_CTX *ctx, int param_enc);
|
||||
|
||||
int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX *ctx, int mbits);
|
||||
int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, BIGNUM *pubexp);
|
||||
|
||||
int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int pad);
|
||||
int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int len);
|
||||
|
||||
int EVP_PKEY_CTX_set_dh_paramgen_prime_len(EVP_PKEY_CTX *ctx, int pbits);
|
||||
]]
|
||||
_M.EVP_PKEY_CTX_set_ec_paramgen_curve_nid = function(pctx, nid)
|
||||
return C.EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid)
|
||||
end
|
||||
_M.EVP_PKEY_CTX_set_ec_param_enc = function(pctx, param_enc)
|
||||
return C.EVP_PKEY_CTX_set_ec_param_enc(pctx, param_enc)
|
||||
end
|
||||
|
||||
_M.EVP_PKEY_CTX_set_rsa_keygen_bits = function(pctx, mbits)
|
||||
return C.EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, mbits)
|
||||
end
|
||||
_M.EVP_PKEY_CTX_set_rsa_keygen_pubexp = function(pctx, pubexp)
|
||||
return C.EVP_PKEY_CTX_set_rsa_keygen_pubexp(pctx, pubexp)
|
||||
end
|
||||
|
||||
_M.EVP_PKEY_CTX_set_rsa_padding = function(pctx, pad)
|
||||
return C.EVP_PKEY_CTX_set_rsa_padding(pctx, pad)
|
||||
end
|
||||
_M.EVP_PKEY_CTX_set_rsa_pss_saltlen = function(pctx, len)
|
||||
return C.EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, len)
|
||||
end
|
||||
_M.EVP_PKEY_CTX_set_dh_paramgen_prime_len = function(pctx, pbits)
|
||||
return C.EVP_PKEY_CTX_set_dh_paramgen_prime_len(pctx, pbits)
|
||||
end
|
||||
|
||||
else
|
||||
_M.EVP_PKEY_CTX_set_ec_paramgen_curve_nid = function(pctx, nid)
|
||||
return C.EVP_PKEY_CTX_ctrl(pctx,
|
||||
evp.EVP_PKEY_EC,
|
||||
evp.EVP_PKEY_OP_PARAMGEN + evp.EVP_PKEY_OP_KEYGEN,
|
||||
evp.EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID,
|
||||
nid, nil)
|
||||
end
|
||||
_M.EVP_PKEY_CTX_set_ec_param_enc = function(pctx, param_enc)
|
||||
return C.EVP_PKEY_CTX_ctrl(pctx,
|
||||
evp.EVP_PKEY_EC,
|
||||
evp.EVP_PKEY_OP_PARAMGEN + evp.EVP_PKEY_OP_KEYGEN,
|
||||
evp.EVP_PKEY_CTRL_EC_PARAM_ENC,
|
||||
param_enc, nil)
|
||||
end
|
||||
|
||||
_M.EVP_PKEY_CTX_set_rsa_keygen_bits = function(pctx, mbits)
|
||||
return C.EVP_PKEY_CTX_ctrl(pctx,
|
||||
evp.EVP_PKEY_RSA,
|
||||
evp.EVP_PKEY_OP_KEYGEN,
|
||||
evp.EVP_PKEY_CTRL_RSA_KEYGEN_BITS,
|
||||
mbits, nil)
|
||||
end
|
||||
_M.EVP_PKEY_CTX_set_rsa_keygen_pubexp = function(pctx, pubexp)
|
||||
return C.EVP_PKEY_CTX_ctrl(pctx,
|
||||
evp.EVP_PKEY_RSA, evp.EVP_PKEY_OP_KEYGEN,
|
||||
evp.EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP,
|
||||
0, pubexp)
|
||||
end
|
||||
|
||||
_M.EVP_PKEY_CTX_set_rsa_padding = function(pctx, pad)
|
||||
return C.EVP_PKEY_CTX_ctrl(pctx,
|
||||
evp.EVP_PKEY_RSA,
|
||||
-1,
|
||||
evp.EVP_PKEY_CTRL_RSA_PADDING,
|
||||
pad, nil)
|
||||
end
|
||||
_M.EVP_PKEY_CTX_set_rsa_pss_saltlen = function(pctx, len)
|
||||
return C.EVP_PKEY_CTX_ctrl(pctx,
|
||||
evp.EVP_PKEY_RSA,
|
||||
evp.EVP_PKEY_OP_SIGN + evp.EVP_PKEY_OP_VERIFY,
|
||||
evp.EVP_PKEY_CTRL_RSA_PSS_SALTLEN,
|
||||
len, nil)
|
||||
end
|
||||
|
||||
_M.EVP_PKEY_CTX_set_dh_paramgen_prime_len = function(pctx, pbits)
|
||||
return C.EVP_PKEY_CTX_ctrl(pctx,
|
||||
evp.EVP_PKEY_DH, evp.EVP_PKEY_OP_PARAMGEN,
|
||||
evp.EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN,
|
||||
pbits, nil)
|
||||
end
|
||||
end
|
||||
|
||||
return _M
|
|
@ -0,0 +1,48 @@
|
|||
local ffi = require "ffi"
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
require "resty.openssl.include.evp"
|
||||
local OPENSSL_10 = require("resty.openssl.version").OPENSSL_10
|
||||
local OPENSSL_11_OR_LATER = require("resty.openssl.version").OPENSSL_11_OR_LATER
|
||||
local BORINGSSL = require("resty.openssl.version").BORINGSSL
|
||||
|
||||
if BORINGSSL then
|
||||
ffi.cdef [[
|
||||
int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len,
|
||||
const EVP_MD *md, ENGINE *impl);
|
||||
]]
|
||||
else
|
||||
ffi.cdef [[
|
||||
int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len,
|
||||
const EVP_MD *md, ENGINE *impl);
|
||||
]]
|
||||
end
|
||||
|
||||
ffi.cdef [[
|
||||
int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data,
|
||||
size_t len);
|
||||
int HMAC_Final(HMAC_CTX *ctx, unsigned char *md,
|
||||
unsigned int *len);
|
||||
]]
|
||||
|
||||
if OPENSSL_11_OR_LATER then
|
||||
ffi.cdef [[
|
||||
HMAC_CTX *HMAC_CTX_new(void);
|
||||
void HMAC_CTX_free(HMAC_CTX *ctx);
|
||||
]]
|
||||
elseif OPENSSL_10 then
|
||||
ffi.cdef [[
|
||||
// # define HMAC_MAX_MD_CBLOCK 128/* largest known is SHA512 */
|
||||
struct hmac_ctx_st {
|
||||
const EVP_MD *md;
|
||||
EVP_MD_CTX md_ctx;
|
||||
EVP_MD_CTX i_ctx;
|
||||
EVP_MD_CTX o_ctx;
|
||||
unsigned int key_length;
|
||||
unsigned char key[128];
|
||||
};
|
||||
|
||||
void HMAC_CTX_init(HMAC_CTX *ctx);
|
||||
void HMAC_CTX_cleanup(HMAC_CTX *ctx);
|
||||
]]
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
local ffi = require "ffi"
|
||||
|
||||
require "resty.openssl.include.ossl_typ"
|
||||
|
||||
ffi.cdef [[
|
||||
int OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *a, int no_name);
|
||||
ASN1_OBJECT *OBJ_txt2obj(const char *s, int no_name);
|
||||
int OBJ_txt2nid(const char *s);
|
||||
const char *OBJ_nid2sn(int n);
|
||||
int OBJ_ln2nid(const char *s);
|
||||
int OBJ_sn2nid(const char *s);
|
||||
const char *OBJ_nid2ln(int n);
|
||||
const char *OBJ_nid2sn(int n);
|
||||
int OBJ_obj2nid(const ASN1_OBJECT *o);
|
||||
const ASN1_OBJECT *OBJ_nid2obj(int n);
|
||||
int OBJ_create(const char *oid, const char *sn, const char *ln);
|
||||
|
||||
int OBJ_find_sigid_algs(int signid, int *pdig_nid, int *ppkey_nid);
|
||||
]]
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue