11local base = require " resty.core.base"
2- base .allows_subsystem (' http' )
3- local debug = require ' debug'
4- local ffi = require ' ffi'
2+ base .allows_subsystem (" http" )
3+ local debug = require " debug"
4+ local ffi = require " ffi"
55
66
7- local error = error
7+ local error = error
8+ local assert = assert
89local tonumber = tonumber
10+ local tostring = tostring
11+ local type = type
12+ local select = select
913local registry = debug.getregistry ()
14+
15+ local C = ffi .C
1016local ffi_new = ffi .new
11- local ffi_string = ffi .string
12- local C = ffi .C
17+ local ffi_str = ffi .string
18+ local ffi_gc = ffi .gc
19+
1320local get_string_buf = base .get_string_buf
14- local get_size_ptr = base .get_size_ptr
15- local tostring = tostring
21+ local get_size_ptr = base .get_size_ptr
22+ local get_request = base .get_request
23+
24+ local co_yield = coroutine ._yield
1625
1726
1827local option_index = {
@@ -35,14 +44,36 @@ ngx_http_lua_ffi_socket_tcp_getoption(ngx_http_lua_socket_tcp_upstream_t *u,
3544int
3645ngx_http_lua_ffi_socket_tcp_setoption (ngx_http_lua_socket_tcp_upstream_t * u ,
3746 int opt , int val , unsigned char * err , size_t * errlen );
47+
48+ int
49+ ngx_http_lua_ffi_socket_tcp_sslhandshake (ngx_http_request_t * r ,
50+ ngx_http_lua_socket_tcp_upstream_t * u , void * sess ,
51+ int enable_session_reuse , ngx_str_t * server_name , int verify ,
52+ int ocsp_status_req , void * chain , void * pkey , char ** errmsg );
53+
54+ int
55+ ngx_http_lua_ffi_socket_tcp_get_sslhandshake_result (ngx_http_request_t * r ,
56+ ngx_http_lua_socket_tcp_upstream_t * u , void ** sess , char ** errmsg ,
57+ int * openssl_error_code );
58+
59+ void
60+ ngx_http_lua_ffi_ssl_free_session (void * sess );
3861]]
3962
4063
4164local output_value_buf = ffi_new (" int[1]" )
42- local FFI_OK = base .FFI_OK
43- local SOCKET_CTX_INDEX = 1
4465local ERR_BUF_SIZE = 4096
4566
67+ local FFI_OK = base .FFI_OK
68+ local FFI_ERROR = base .FFI_ERROR
69+ local FFI_DONE = base .FFI_DONE
70+ local FFI_AGAIN = base .FFI_AGAIN
71+ local FFI_NO_REQ_CTX = base .FFI_NO_REQ_CTX
72+
73+ local SOCKET_CTX_INDEX = 1
74+ local SOCKET_CLIENT_CERT_INDEX = 6
75+ local SOCKET_CLIENT_PKEY_INDEX = 7
76+
4677
4778local function get_tcp_socket (cosocket )
4879 local tcp_socket = cosocket [SOCKET_CTX_INDEX ]
@@ -75,7 +106,7 @@ local function getoption(cosocket, option)
75106 err ,
76107 errlen )
77108 if rc ~= FFI_OK then
78- return nil , ffi_string (err , errlen [0 ])
109+ return nil , ffi_str (err , errlen [0 ])
79110 end
80111
81112 return tonumber (output_value_buf [0 ])
@@ -107,17 +138,134 @@ local function setoption(cosocket, option, value)
107138 err ,
108139 errlen )
109140 if rc ~= FFI_OK then
110- return nil , ffi_string (err , errlen [0 ])
141+ return nil , ffi_str (err , errlen [0 ])
111142 end
112143
113144 return true
114145end
115146
116147
148+ local errmsg = base .get_errmsg_ptr ()
149+ local session_ptr = ffi_new (" void *[1]" )
150+ local server_name_str = ffi_new (" ngx_str_t[1]" )
151+ local openssl_error_code = ffi_new (" int[1]" )
152+
153+
154+ local function setclientcert (cosocket , cert , pkey )
155+ if not cert and not pkey then
156+ cosocket [SOCKET_CLIENT_CERT_INDEX ] = nil
157+ cosocket [SOCKET_CLIENT_PKEY_INDEX ] = nil
158+ return true
159+ end
160+
161+ if not cert or not pkey then
162+ return nil ,
163+ " client certificate must be supplied with corresponding " ..
164+ " private key"
165+ end
166+
167+ if type (cert ) ~= " cdata" then
168+ return nil , " bad cert arg: cdata expected, got " .. type (cert )
169+ end
170+
171+ if type (pkey ) ~= " cdata" then
172+ return nil , " bad pkey arg: cdata expected, got " .. type (pkey )
173+ end
174+
175+ cosocket [SOCKET_CLIENT_CERT_INDEX ] = cert
176+ cosocket [SOCKET_CLIENT_PKEY_INDEX ] = pkey
177+
178+ return true
179+ end
180+
181+
182+ local function sslhandshake (cosocket , reused_session , server_name , ssl_verify ,
183+ send_status_req , ...)
184+
185+ local n = select (" #" , ... )
186+ if not cosocket or n > 0 then
187+ error (" ngx.socket sslhandshake: expecting 1 ~ 5 arguments " ..
188+ " (including the object), but seen " .. (cosocket and 5 + n or 0 ))
189+ end
190+
191+ local r = get_request ()
192+ if not r then
193+ error (" no request found" , 2 )
194+ end
195+
196+ session_ptr [0 ] = type (reused_session ) == " cdata" and reused_session or nil
197+
198+ if server_name then
199+ server_name_str [0 ].data = server_name
200+ server_name_str [0 ].len = # server_name
201+
202+ else
203+ server_name_str [0 ].data = nil
204+ server_name_str [0 ].len = 0
205+ end
206+
207+ local u = get_tcp_socket (cosocket )
208+
209+ local rc = C .ngx_http_lua_ffi_socket_tcp_sslhandshake (r , u ,
210+ session_ptr [0 ],
211+ reused_session ~= false ,
212+ server_name_str ,
213+ ssl_verify and 1 or 0 ,
214+ send_status_req and 1 or 0 ,
215+ cosocket [SOCKET_CLIENT_CERT_INDEX ],
216+ cosocket [SOCKET_CLIENT_PKEY_INDEX ],
217+ errmsg )
218+
219+ if rc == FFI_NO_REQ_CTX then
220+ error (" no request ctx found" , 2 )
221+ end
222+
223+ while true do
224+ if rc == FFI_ERROR then
225+ if openssl_error_code [0 ] ~= 0 then
226+ return nil , openssl_error_code [0 ] .. " : " .. ffi_str (errmsg [0 ])
227+ end
228+
229+ return nil , ffi_str (errmsg [0 ])
230+ end
231+
232+ if rc == FFI_DONE then
233+ return reused_session
234+ end
235+
236+ if rc == FFI_OK then
237+ if reused_session == false then
238+ return true
239+ end
240+
241+ rc = C .ngx_http_lua_ffi_socket_tcp_get_sslhandshake_result (r , u ,
242+ session_ptr , errmsg , openssl_error_code )
243+
244+ assert (rc == FFI_OK )
245+
246+ if session_ptr [0 ] == nil then
247+ return session_ptr [0 ]
248+ end
249+
250+ return ffi_gc (session_ptr [0 ], C .ngx_http_lua_ffi_ssl_free_session )
251+ end
252+
253+ assert (rc == FFI_AGAIN )
254+
255+ co_yield ()
256+
257+ rc = C .ngx_http_lua_ffi_socket_tcp_get_sslhandshake_result (r , u ,
258+ session_ptr , errmsg , openssl_error_code )
259+ end
260+ end
261+
262+
117263do
118264 local method_table = registry .__tcp_cosocket_mt
119265 method_table .getoption = getoption
120266 method_table .setoption = setoption
267+ method_table .setclientcert = setclientcert
268+ method_table .sslhandshake = sslhandshake
121269end
122270
123271
0 commit comments