mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
Squashed 'src/deps/src/lua-resty-http/' changes from 4ab4269cf..183310324
183310324 Bump version bf3e411a9 fix some return value errors f2f7460db fixup dbc6ba21b use `..` concat operation to keep the original style 52f83bbde fix error message 7624d2094 fix error message 814f2aeb5 fix test f7a7af18d fix typo a62778ca2 error out directly for other cases as well and fix test 310e78dd8 load resty.openssl.* at the module level and error out if the client cert set isn't valid 836569d0e apply the comment 57dae629a apply comments 5455eee45 apply the comments bdaf80adc add debug log to print poolname a939c7efe fallback to non-mTLS when any cert/key error and log a warning be15d2ae6 add type check for client cert and key 08ad5111d add the latest openresty versions and skip mtls tests only when nginx version < 1.21.4 af9d005c6 fix: use the correct chain path and add `ffi.cast` a4873ce7d fix: ssl_client_cert is a chain of x509 instead of a x509 c83c9e27b add test 7598cbe99 check the private key in order to make sure the caller is indeed the holder of the cert 8194773cb fix poolname to include the digest of the cert for mTLS git-subtree-dir: src/deps/src/lua-resty-http git-subtree-split: 183310324026120ab7eaf5dd82b9be90ae63aadf
This commit is contained in:
parent
7160fd94e3
commit
6c42ecd81d
6 changed files with 204 additions and 19 deletions
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
|
|
@ -20,6 +20,8 @@ jobs:
|
|||
openresty_version:
|
||||
- 1.17.8.2
|
||||
- 1.19.9.1
|
||||
- 1.21.4.3
|
||||
- 1.25.3.1
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
|
|
@ -49,7 +51,9 @@ jobs:
|
|||
run: cpanm -q -n Test::Nginx
|
||||
|
||||
- name: Install Luacov
|
||||
run: /usr/local/openresty/luajit/bin/luarocks install luacov
|
||||
run: |
|
||||
/usr/local/openresty/luajit/bin/luarocks install luacov
|
||||
/usr/local/openresty/luajit/bin/luarocks install lua-resty-openssl
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ end
|
|||
|
||||
|
||||
local _M = {
|
||||
_VERSION = '0.17.1',
|
||||
_VERSION = '0.17.2',
|
||||
}
|
||||
_M._USER_AGENT = "lua-resty-http/" .. _M._VERSION .. " (Lua) ngx_lua/" .. ngx.config.ngx_lua_version
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,26 @@
|
|||
local ffi = require "ffi"
|
||||
local ngx_re_gmatch = ngx.re.gmatch
|
||||
local ngx_re_sub = ngx.re.sub
|
||||
local ngx_re_find = ngx.re.find
|
||||
local ngx_log = ngx.log
|
||||
local ngx_WARN = ngx.WARN
|
||||
local ngx_DEBUG = ngx.DEBUG
|
||||
local to_hex = require("resty.string").to_hex
|
||||
local ffi_gc = ffi.gc
|
||||
local ffi_cast = ffi.cast
|
||||
local type = type
|
||||
|
||||
local lib_chain, lib_x509, lib_pkey
|
||||
local openssl_available, res = xpcall(function()
|
||||
lib_chain = require("resty.openssl.x509.chain")
|
||||
lib_x509 = require("resty.openssl.x509")
|
||||
lib_pkey = require("resty.openssl.pkey")
|
||||
end, debug.traceback)
|
||||
|
||||
if not openssl_available then
|
||||
ngx_log(ngx_WARN, "failed to load module `resty.openssl.*`, \z
|
||||
mTLS isn't supported without lua-resty-openssl:\n", res)
|
||||
end
|
||||
|
||||
--[[
|
||||
A connection function that incorporates:
|
||||
|
|
@ -148,7 +166,7 @@ local function connect(self, options)
|
|||
local proxy_uri_t
|
||||
proxy_uri_t, err = self:parse_uri(proxy_uri)
|
||||
if not proxy_uri_t then
|
||||
return nil, "uri parse error: ", err
|
||||
return nil, "uri parse error: " .. err
|
||||
end
|
||||
|
||||
local proxy_scheme = proxy_uri_t[1]
|
||||
|
|
@ -160,6 +178,61 @@ local function connect(self, options)
|
|||
proxy_port = proxy_uri_t[3]
|
||||
end
|
||||
|
||||
local cert_hash
|
||||
if ssl and ssl_client_cert and ssl_client_priv_key then
|
||||
local cert_type = type(ssl_client_cert)
|
||||
local key_type = type(ssl_client_priv_key)
|
||||
|
||||
if cert_type ~= "cdata" then
|
||||
return nil, "bad ssl_client_cert: cdata expected, got " .. cert_type
|
||||
end
|
||||
|
||||
if key_type ~= "cdata" then
|
||||
return nil, "bad ssl_client_priv_key: cdata expected, got " .. key_type
|
||||
end
|
||||
|
||||
if not openssl_available then
|
||||
return nil, "module `resty.openssl.*` not available, mTLS isn't supported without lua-resty-openssl"
|
||||
end
|
||||
|
||||
-- convert from `void*` to `OPENSSL_STACK*`
|
||||
local cert_chain, err = lib_chain.dup(ffi_cast("OPENSSL_STACK*", ssl_client_cert))
|
||||
if not cert_chain then
|
||||
return nil, "failed to dup the ssl_client_cert: " .. err
|
||||
end
|
||||
|
||||
if #cert_chain < 1 then
|
||||
return nil, "no cert in ssl_client_cert"
|
||||
end
|
||||
|
||||
local cert, err = lib_x509.dup(cert_chain[1].ctx)
|
||||
if not cert then
|
||||
return nil, "failed to dup the x509: " .. err
|
||||
end
|
||||
|
||||
-- convert from `void*` to `EVP_PKEY*`
|
||||
local key, err = lib_pkey.new(ffi_cast("EVP_PKEY*", ssl_client_priv_key))
|
||||
if not key then
|
||||
return nil, "failed to new the pkey: " .. err
|
||||
end
|
||||
|
||||
-- should not free the cdata passed in
|
||||
ffi_gc(key.ctx, nil)
|
||||
|
||||
-- check the private key in order to make sure the caller is indeed the holder of the cert
|
||||
ok, err = cert:check_private_key(key)
|
||||
if not ok then
|
||||
return nil, "the private key doesn't match the cert: " .. err
|
||||
end
|
||||
|
||||
cert_hash, err = cert:digest("sha256")
|
||||
if not cert_hash then
|
||||
return nil, "failed to calculate the digest of the cert: " .. err
|
||||
end
|
||||
|
||||
cert_hash = to_hex(cert_hash) -- convert to hex so that it's printable
|
||||
end
|
||||
|
||||
-- construct a poolname unique within proxy and ssl info
|
||||
if not poolname then
|
||||
poolname = (request_scheme or "")
|
||||
|
|
@ -170,12 +243,15 @@ local function connect(self, options)
|
|||
.. ":" .. tostring(ssl_verify)
|
||||
.. ":" .. (proxy_uri or "")
|
||||
.. ":" .. (request_scheme == "https" and proxy_authorization or "")
|
||||
.. ":" .. (cert_hash or "")
|
||||
-- in the above we only add the 'proxy_authorization' as part of the poolname
|
||||
-- when the request is https. Because in that case the CONNECT request (which
|
||||
-- carries the authorization header) is part of the connect procedure, whereas
|
||||
-- with a plain http request the authorization is part of the actual request.
|
||||
end
|
||||
|
||||
ngx_log(ngx_DEBUG, "poolname: ", poolname)
|
||||
|
||||
-- do TCP level connection
|
||||
local tcp_opts = { pool = poolname, pool_size = pool_size, backlog = backlog }
|
||||
if proxy then
|
||||
|
|
@ -184,7 +260,7 @@ local function connect(self, options)
|
|||
if not ok then
|
||||
return nil, "failed to connect to: " .. (proxy_host or "") ..
|
||||
":" .. (proxy_port or "") ..
|
||||
": ", err
|
||||
": " .. err
|
||||
end
|
||||
|
||||
if ssl and sock:getreusedtimes() == 0 then
|
||||
|
|
@ -204,7 +280,7 @@ local function connect(self, options)
|
|||
})
|
||||
|
||||
if not res then
|
||||
return nil, "failed to issue CONNECT to proxy:", err
|
||||
return nil, "failed to issue CONNECT to proxy: " .. err
|
||||
end
|
||||
|
||||
if res.status < 200 or res.status > 299 then
|
||||
|
|
@ -234,13 +310,13 @@ local function connect(self, options)
|
|||
-- Experimental mTLS support
|
||||
if ssl_client_cert and ssl_client_priv_key then
|
||||
if type(sock.setclientcert) ~= "function" then
|
||||
ngx_log(ngx_WARN, "cannot use SSL client cert and key without mTLS support")
|
||||
return nil, "cannot use SSL client cert and key without mTLS support"
|
||||
|
||||
else
|
||||
ok, err = sock:setclientcert(ssl_client_cert, ssl_client_priv_key)
|
||||
if not ok then
|
||||
ngx_log(ngx_WARN, "could not set client certificate: ", err)
|
||||
end
|
||||
ok, err = sock:setclientcert(ssl_client_cert, ssl_client_priv_key)
|
||||
if not ok then
|
||||
return nil, "could not set client certificate: " .. err
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ local rawget, rawset, setmetatable =
|
|||
local str_lower = string.lower
|
||||
|
||||
local _M = {
|
||||
_VERSION = '0.17.1',
|
||||
_VERSION = '0.17.2',
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package = "lua-resty-http"
|
||||
version = "0.17.1-0"
|
||||
version = "0.17.2-0"
|
||||
source = {
|
||||
url = "git://github.com/ledgetech/lua-resty-http",
|
||||
tag = "v0.17.1"
|
||||
tag = "v0.17.2"
|
||||
}
|
||||
description = {
|
||||
summary = "Lua HTTP client cosocket driver for OpenResty / ngx_lua.",
|
||||
117
t/20-mtls.t
117
t/20-mtls.t
|
|
@ -105,7 +105,6 @@ GET /t
|
|||
|
||||
=== TEST 2: Connection fails during handshake with not priv_key
|
||||
--- http_config eval: $::mtls_http_config
|
||||
--- SKIP
|
||||
--- config eval
|
||||
"
|
||||
lua_ssl_trusted_certificate $::HtmlDir/test.crt;
|
||||
|
|
@ -138,6 +137,9 @@ location /t {
|
|||
})
|
||||
|
||||
ngx.say(res:read_body())
|
||||
|
||||
else
|
||||
ngx.say('failed to connect: ' .. (err or ''))
|
||||
end
|
||||
|
||||
httpc:close()
|
||||
|
|
@ -148,13 +150,16 @@ location /t {
|
|||
--- request
|
||||
GET /t
|
||||
--- error_code: 200
|
||||
--- error_log
|
||||
could not set client certificate: bad client pkey type
|
||||
--- response_body_unlike: hello, CN=foo@example.com,O=OpenResty,ST=California,C=US
|
||||
--- no_error_log
|
||||
[error]
|
||||
[warn]
|
||||
--- response_body
|
||||
failed to connect: bad ssl_client_priv_key: cdata expected, got string
|
||||
--- skip_nginx
|
||||
4: < 1.21.4
|
||||
|
||||
|
||||
=== TEST 3: Connection succeeds with client cert and key. SKIP'd for CI until feature is merged.
|
||||
--- SKIP
|
||||
=== TEST 3: Connection succeeds with client cert and key.
|
||||
--- http_config eval: $::mtls_http_config
|
||||
--- config eval
|
||||
"
|
||||
|
|
@ -208,4 +213,104 @@ GET /t
|
|||
[warn]
|
||||
--- response_body
|
||||
hello, CN=foo@example.com,O=OpenResty,ST=California,C=US
|
||||
--- skip_nginx
|
||||
4: < 1.21.4
|
||||
|
||||
=== TEST 4: users with different client certs should not share the same pool.
|
||||
--- http_config eval: $::mtls_http_config
|
||||
--- config eval
|
||||
"
|
||||
lua_ssl_trusted_certificate $::HtmlDir/test.crt;
|
||||
|
||||
location /t {
|
||||
content_by_lua_block {
|
||||
local f = assert(io.open('$::HtmlDir/mtls_client.crt'))
|
||||
local cert_data = f:read('*a')
|
||||
f:close()
|
||||
|
||||
f = assert(io.open('$::HtmlDir/mtls_client.key'))
|
||||
local key_data = f:read('*a')
|
||||
f:close()
|
||||
|
||||
local ssl = require('ngx.ssl')
|
||||
|
||||
local cert = assert(ssl.parse_pem_cert(cert_data))
|
||||
local key = assert(ssl.parse_pem_priv_key(key_data))
|
||||
|
||||
f = assert(io.open('$::HtmlDir/test.crt'))
|
||||
local invalid_cert_data = f:read('*a')
|
||||
f:close()
|
||||
|
||||
f = assert(io.open('$::HtmlDir/test.key'))
|
||||
local invalid_key_data = f:read('*a')
|
||||
f:close()
|
||||
|
||||
local invalid_cert = assert(ssl.parse_pem_cert(invalid_cert_data))
|
||||
local invalid_key = assert(ssl.parse_pem_priv_key(invalid_key_data))
|
||||
|
||||
local httpc = assert(require('resty.http').new())
|
||||
|
||||
local ok, err = httpc:connect {
|
||||
scheme = 'https',
|
||||
host = 'unix:$::HtmlDir/mtls.sock',
|
||||
ssl_client_cert = cert,
|
||||
ssl_client_priv_key = key,
|
||||
}
|
||||
|
||||
if ok and not err then
|
||||
local res, err = assert(httpc:request {
|
||||
method = 'GET',
|
||||
path = '/',
|
||||
headers = {
|
||||
['Host'] = 'example.com',
|
||||
},
|
||||
})
|
||||
|
||||
ngx.say(res:read_body())
|
||||
end
|
||||
|
||||
httpc:set_keepalive()
|
||||
|
||||
local httpc = assert(require('resty.http').new())
|
||||
|
||||
local ok, err = httpc:connect {
|
||||
scheme = 'https',
|
||||
host = 'unix:$::HtmlDir/mtls.sock',
|
||||
ssl_client_cert = invalid_cert,
|
||||
ssl_client_priv_key = invalid_key,
|
||||
}
|
||||
|
||||
ngx.say(httpc:get_reused_times())
|
||||
ngx.say(ok)
|
||||
ngx.say(err)
|
||||
|
||||
if ok and not err then
|
||||
local res, err = assert(httpc:request {
|
||||
method = 'GET',
|
||||
path = '/',
|
||||
headers = {
|
||||
['Host'] = 'example.com',
|
||||
},
|
||||
})
|
||||
|
||||
ngx.say(res.status) -- expect 400
|
||||
end
|
||||
|
||||
httpc:close()
|
||||
}
|
||||
}
|
||||
"
|
||||
--- user_files eval: $::mtls_user_files
|
||||
--- request
|
||||
GET /t
|
||||
--- no_error_log
|
||||
[error]
|
||||
[warn]
|
||||
--- response_body
|
||||
hello, CN=foo@example.com,O=OpenResty,ST=California,C=US
|
||||
0
|
||||
true
|
||||
nil
|
||||
400
|
||||
--- skip_nginx
|
||||
4: < 1.21.4
|
||||
|
|
|
|||
Loading…
Reference in a new issue