Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: add function tcpsock:setclientcert, reimplemented tcpsock:sslhandshake with FFI. #278

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ install:
- git clone https://github.com/openresty/openresty.git ../openresty
- git clone https://github.com/openresty/openresty-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
- git clone -b feat/cosocket_tlshandshake https://github.com/dndx/lua-nginx-module.git ../lua-nginx-module

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will need updating before merging.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should do it after we get the official confirm of openresty.

- git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx
- git clone https://github.com/openresty/echo-nginx-module.git ../echo-nginx-module
- git clone https://github.com/openresty/lua-resty-lrucache.git
Expand Down
2 changes: 2 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,8 @@ in the current request before you reusing the `ctx` table in some other place.
## resty.core.socket

* [socket.setoption](https://github.com/openresty/lua-nginx-module#tcpsocksetoption)
* [socket.setclientcert](https://github.com/openresty/lua-nginx-module#tcpsocksetclientcert)
* [socket.sslhandshake](https://github.com/openresty/lua-nginx-module#tcpsocksslhandshake)

[Back to TOC](#table-of-contents)

Expand Down
172 changes: 160 additions & 12 deletions lib/resty/core/socket.lua
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
local base = require "resty.core.base"
base.allows_subsystem('http')
local debug = require 'debug'
local ffi = require 'ffi'
base.allows_subsystem("http")
local debug = require "debug"
local ffi = require "ffi"


local error = error
local error = error
local assert = assert
local tonumber = tonumber
local tostring = tostring
local type = type
local select = select
local registry = debug.getregistry()

local C = ffi.C
local ffi_new = ffi.new
local ffi_string = ffi.string
local C = ffi.C
local ffi_str = ffi.string
local ffi_gc = ffi.gc

local get_string_buf = base.get_string_buf
local get_size_ptr = base.get_size_ptr
local tostring = tostring
local get_size_ptr = base.get_size_ptr
local get_request = base.get_request

local co_yield = coroutine._yield


local option_index = {
Expand All @@ -35,14 +44,36 @@ ngx_http_lua_ffi_socket_tcp_getoption(ngx_http_lua_socket_tcp_upstream_t *u,
int
ngx_http_lua_ffi_socket_tcp_setoption(ngx_http_lua_socket_tcp_upstream_t *u,
int opt, int val, unsigned char *err, size_t *errlen);

int
ngx_http_lua_ffi_socket_tcp_sslhandshake(ngx_http_request_t *r,
ngx_http_lua_socket_tcp_upstream_t *u, void *sess,
int enable_session_reuse, ngx_str_t *server_name, int verify,
int ocsp_status_req, void *chain, void *pkey, char **errmsg);

int
ngx_http_lua_ffi_socket_tcp_get_sslhandshake_result(ngx_http_request_t *r,
ngx_http_lua_socket_tcp_upstream_t *u, void **sess, char **errmsg,
int *openssl_error_code);

void
ngx_http_lua_ffi_ssl_free_session(void *sess);
]]


local output_value_buf = ffi_new("int[1]")
local FFI_OK = base.FFI_OK
local SOCKET_CTX_INDEX = 1
local ERR_BUF_SIZE = 4096

local FFI_OK = base.FFI_OK
local FFI_ERROR = base.FFI_ERROR
local FFI_DONE = base.FFI_DONE
local FFI_AGAIN = base.FFI_AGAIN
local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX

local SOCKET_CTX_INDEX = 1
local SOCKET_CLIENT_CERT_INDEX = 6
local SOCKET_CLIENT_PKEY_INDEX = 7


local function get_tcp_socket(cosocket)
local tcp_socket = cosocket[SOCKET_CTX_INDEX]
Expand Down Expand Up @@ -75,7 +106,7 @@ local function getoption(cosocket, option)
err,
errlen)
if rc ~= FFI_OK then
return nil, ffi_string(err, errlen[0])
return nil, ffi_str(err, errlen[0])
end

return tonumber(output_value_buf[0])
Expand Down Expand Up @@ -107,17 +138,134 @@ local function setoption(cosocket, option, value)
err,
errlen)
if rc ~= FFI_OK then
return nil, ffi_string(err, errlen[0])
return nil, ffi_str(err, errlen[0])
end

return true
end


local errmsg = base.get_errmsg_ptr()
local session_ptr = ffi_new("void *[1]")
local server_name_str = ffi_new("ngx_str_t[1]")
local openssl_error_code = ffi_new("int[1]")


local function setclientcert(cosocket, cert, pkey)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
local function setclientcert(cosocket, cert, pkey)
local function set_client_cert(cosocket, cert, pkey)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to keep the style consistent with existing cosocket API function names. e.g. tcpsock:getreusedtimes

if not cert and not pkey then
cosocket[SOCKET_CLIENT_CERT_INDEX] = nil
cosocket[SOCKET_CLIENT_PKEY_INDEX] = nil
return true
end

if not cert or not pkey then
return nil,
"client certificate must be supplied with corresponding " ..
"private key"
end

if type(cert) ~= "cdata" then
return nil, "bad cert arg: cdata expected, got " .. type(cert)
end

if type(pkey) ~= "cdata" then
return nil, "bad pkey arg: cdata expected, got " .. type(pkey)
end

cosocket[SOCKET_CLIENT_CERT_INDEX] = cert
cosocket[SOCKET_CLIENT_PKEY_INDEX] = pkey

return true
end
dndx marked this conversation as resolved.
Show resolved Hide resolved


local function sslhandshake(cosocket, reused_session, server_name, ssl_verify,
send_status_req, ...)

local n = select("#", ...)
if not cosocket or n > 0 then
error("ngx.socket sslhandshake: expecting 1 ~ 5 arguments " ..
"(including the object), but seen " .. (cosocket and 5 + n or 0))
end

local r = get_request()
if not r then
error("no request found", 2)
end

session_ptr[0] = type(reused_session) == "cdata" and reused_session or nil

if server_name then
server_name_str[0].data = server_name
server_name_str[0].len = #server_name

else
server_name_str[0].data = nil
server_name_str[0].len = 0
end

local u = get_tcp_socket(cosocket)

local rc = C.ngx_http_lua_ffi_socket_tcp_sslhandshake(r, u,
session_ptr[0],
reused_session ~= false,
server_name_str,
ssl_verify and 1 or 0,
send_status_req and 1 or 0,
cosocket[SOCKET_CLIENT_CERT_INDEX],
cosocket[SOCKET_CLIENT_PKEY_INDEX],
errmsg)

if rc == FFI_NO_REQ_CTX then
error("no request ctx found", 2)
end

while true do
dndx marked this conversation as resolved.
Show resolved Hide resolved
if rc == FFI_ERROR then
if openssl_error_code[0] ~= 0 then
return nil, openssl_error_code[0] .. ": " .. ffi_str(errmsg[0])
end

return nil, ffi_str(errmsg[0])
end

if rc == FFI_DONE then
return reused_session
end

if rc == FFI_OK then
if reused_session == false then
return true
end

rc = C.ngx_http_lua_ffi_socket_tcp_get_sslhandshake_result(r, u,
session_ptr, errmsg, openssl_error_code)

assert(rc == FFI_OK)

if session_ptr[0] == nil then
return session_ptr[0]
end

return ffi_gc(session_ptr[0], C.ngx_http_lua_ffi_ssl_free_session)
end

assert(rc == FFI_AGAIN)

co_yield()

rc = C.ngx_http_lua_ffi_socket_tcp_get_sslhandshake_result(r, u,
dndx marked this conversation as resolved.
Show resolved Hide resolved
session_ptr, errmsg, openssl_error_code)
end
end


do
local method_table = registry.__tcp_cosocket_mt
method_table.getoption = getoption
method_table.setoption = setoption
method_table.setclientcert = setclientcert
method_table.sslhandshake = sslhandshake
end


Expand Down
30 changes: 15 additions & 15 deletions t/ocsp.t
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ __DATA__
GET /t
--- response_body
connected: 1
ssl handshake: userdata
ssl handshake: cdata

--- error_log
lua ssl server name: "test.com"
Expand Down Expand Up @@ -189,7 +189,7 @@ OCSP url found: http://127.0.0.1:8888/ocsp?foo=1,
GET /t
--- response_body
connected: 1
ssl handshake: userdata
ssl handshake: cdata

--- error_log
lua ssl server name: "test.com"
Expand Down Expand Up @@ -281,7 +281,7 @@ OCSP responder not found
GET /t
--- response_body
connected: 1
ssl handshake: userdata
ssl handshake: cdata

--- error_log
lua ssl server name: "test.com"
Expand Down Expand Up @@ -372,7 +372,7 @@ failed to get OCSP responder: no issuer certificate in chain
GET /t
--- response_body
connected: 1
ssl handshake: userdata
ssl handshake: cdata

--- error_log
lua ssl server name: "test.com"
Expand Down Expand Up @@ -467,7 +467,7 @@ failed to get OCSP responder: issuer certificate not next to leaf
GET /t
--- response_body
connected: 1
ssl handshake: userdata
ssl handshake: cdata

--- error_log
lua ssl server name: "test.com"
Expand Down Expand Up @@ -564,7 +564,7 @@ still get an error: truncated
GET /t
--- response_body
connected: 1
ssl handshake: userdata
ssl handshake: cdata

--- error_log
lua ssl server name: "test.com"
Expand Down Expand Up @@ -657,7 +657,7 @@ OCSP request created with length 68
GET /t
--- response_body
connected: 1
ssl handshake: userdata
ssl handshake: cdata

--- error_log
lua ssl server name: "test.com"
Expand Down Expand Up @@ -831,7 +831,7 @@ failed to create OCSP request: d2i_X509_bio() failed
GET /t
--- response_body
connected: 1
ssl handshake: userdata
ssl handshake: cdata

--- error_log
lua ssl server name: "test.com"
Expand Down Expand Up @@ -922,7 +922,7 @@ failed to create OCSP request: no issuer certificate in chain
GET /t
--- response_body
connected: 1
ssl handshake: userdata
ssl handshake: cdata

--- error_log
lua ssl server name: "test.com"
Expand Down Expand Up @@ -1015,7 +1015,7 @@ OCSP response validation ok
GET /t
--- response_body
connected: 1
ssl handshake: userdata
ssl handshake: cdata

--- error_log
lua ssl server name: "test.com"
Expand Down Expand Up @@ -1107,7 +1107,7 @@ OCSP response validation ok
GET /t
--- response_body
connected: 1
ssl handshake: userdata
ssl handshake: cdata

--- error_log
lua ssl server name: "test.com"
Expand Down Expand Up @@ -1202,7 +1202,7 @@ FIXME: we should complain in this case.
GET /t
--- response_body
connected: 1
ssl handshake: userdata
ssl handshake: cdata

--- error_log
lua ssl server name: "test.com"
Expand Down Expand Up @@ -1296,7 +1296,7 @@ OCSP response validation ok
GET /t
--- response_body
connected: 1
ssl handshake: userdata
ssl handshake: cdata

--- error_log
lua ssl server name: "test.com"
Expand Down Expand Up @@ -1472,7 +1472,7 @@ FIXME: check the OCSP staple actually received by the ssl client
GET /t
--- response_body
connected: 1
ssl handshake: userdata
ssl handshake: cdata

--- error_log
lua ssl server name: "test.com"
Expand Down Expand Up @@ -1554,7 +1554,7 @@ ocsp status resp set ok: nil,
GET /t
--- response_body
connected: 1
ssl handshake: userdata
ssl handshake: cdata

--- error_log
lua ssl server name: "test.com"
Expand Down
Loading