|
| 1 | +local ffi = require "ffi" |
1 | 2 | local ngx_re_gmatch = ngx.re.gmatch |
2 | 3 | local ngx_re_sub = ngx.re.sub |
3 | 4 | local ngx_re_find = ngx.re.find |
4 | 5 | local ngx_log = ngx.log |
5 | 6 | local ngx_WARN = ngx.WARN |
| 7 | +local to_hex = require("resty.string").to_hex |
| 8 | +local ffi_gc = ffi.gc |
| 9 | +local string_format = string.format |
6 | 10 |
|
7 | 11 | --[[ |
8 | 12 | A connection function that incorporates: |
@@ -160,16 +164,51 @@ local function connect(self, options) |
160 | 164 | proxy_port = proxy_uri_t[3] |
161 | 165 | end |
162 | 166 |
|
| 167 | + local cert_hash |
| 168 | + if ssl and ssl_client_cert and ssl_client_priv_key then |
| 169 | + local status, res = xpcall(function() |
| 170 | + return require("resty.openssl.x509") |
| 171 | + end, debug.traceback) |
| 172 | + |
| 173 | + if status then |
| 174 | + local x509 = res |
| 175 | + local cert, err = x509.new(ssl_client_cert) |
| 176 | + if not cert then |
| 177 | + return nil, err |
| 178 | + end |
| 179 | + -- should not free the cdata passed in |
| 180 | + ffi_gc(cert.ctx, nil) |
| 181 | + |
| 182 | + cert_hash, err = cert:digest("sha256") |
| 183 | + if cert_hash then |
| 184 | + cert_hash = to_hex(cert_hash) -- convert to hex so that it's printable |
| 185 | + |
| 186 | + else |
| 187 | + return nil, err |
| 188 | + end |
| 189 | + |
| 190 | + else |
| 191 | + if type(res) == "string" and ngx_re_find(res, "module 'resty\\.openssl\\.x509)' not found") then |
| 192 | + ngx_log(ngx_WARN, "can't use mTLS without module `lua-resty-openssl`, falling back to non-mTLS.") |
| 193 | + |
| 194 | + else |
| 195 | + return nil, "failed to load module 'resty.openssl.x509':\n" .. res |
| 196 | + end |
| 197 | + end |
| 198 | + end |
| 199 | + |
163 | 200 | -- construct a poolname unique within proxy and ssl info |
164 | 201 | if not poolname then |
165 | | - poolname = (request_scheme or "") |
166 | | - .. ":" .. request_host |
167 | | - .. ":" .. tostring(request_port) |
168 | | - .. ":" .. tostring(ssl) |
169 | | - .. ":" .. (ssl_server_name or "") |
170 | | - .. ":" .. tostring(ssl_verify) |
171 | | - .. ":" .. (proxy_uri or "") |
172 | | - .. ":" .. (request_scheme == "https" and proxy_authorization or "") |
| 202 | + poolname = string_format("%s:%s:%s:%s:%s:%s:%s:%s:%s", |
| 203 | + request_scheme or "", |
| 204 | + request_host, |
| 205 | + tostring(request_port), |
| 206 | + tostring(ssl), |
| 207 | + ssl_server_name or "", |
| 208 | + tostring(ssl_verify), |
| 209 | + proxy_uri or "", |
| 210 | + request_scheme == "https" and proxy_authorization or "", |
| 211 | + cert_hash or "") |
173 | 212 | -- in the above we only add the 'proxy_authorization' as part of the poolname |
174 | 213 | -- when the request is https. Because in that case the CONNECT request (which |
175 | 214 | -- carries the authorization header) is part of the connect procedure, whereas |
|
0 commit comments