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:
Théophile Diot 2024-03-07 13:23:46 +00:00
parent 7160fd94e3
commit 6c42ecd81d
6 changed files with 204 additions and 19 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -4,7 +4,7 @@ local rawget, rawset, setmetatable =
local str_lower = string.lower
local _M = {
_VERSION = '0.17.1',
_VERSION = '0.17.2',
}

View file

@ -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.",

View file

@ -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