1
1
local 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"
5
5
6
6
7
- local error = error
7
+ local error = error
8
+ local assert = assert
8
9
local tonumber = tonumber
10
+ local tostring = tostring
11
+ local type = type
12
+ local select = select
9
13
local registry = debug.getregistry ()
14
+
15
+ local C = ffi .C
10
16
local 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
+
13
20
local 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
16
25
17
26
18
27
local option_index = {
@@ -35,14 +44,36 @@ ngx_http_lua_ffi_socket_tcp_getoption(ngx_http_lua_socket_tcp_upstream_t *u,
35
44
int
36
45
ngx_http_lua_ffi_socket_tcp_setoption (ngx_http_lua_socket_tcp_upstream_t * u ,
37
46
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 );
38
61
]]
39
62
40
63
41
64
local output_value_buf = ffi_new (" int[1]" )
42
- local FFI_OK = base .FFI_OK
43
- local SOCKET_CTX_INDEX = 1
44
65
local ERR_BUF_SIZE = 4096
45
66
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
+
46
77
47
78
local function get_tcp_socket (cosocket )
48
79
local tcp_socket = cosocket [SOCKET_CTX_INDEX ]
@@ -75,7 +106,7 @@ local function getoption(cosocket, option)
75
106
err ,
76
107
errlen )
77
108
if rc ~= FFI_OK then
78
- return nil , ffi_string (err , errlen [0 ])
109
+ return nil , ffi_str (err , errlen [0 ])
79
110
end
80
111
81
112
return tonumber (output_value_buf [0 ])
@@ -107,17 +138,134 @@ local function setoption(cosocket, option, value)
107
138
err ,
108
139
errlen )
109
140
if rc ~= FFI_OK then
110
- return nil , ffi_string (err , errlen [0 ])
141
+ return nil , ffi_str (err , errlen [0 ])
111
142
end
112
143
113
144
return true
114
145
end
115
146
116
147
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
+
117
263
do
118
264
local method_table = registry .__tcp_cosocket_mt
119
265
method_table .getoption = getoption
120
266
method_table .setoption = setoption
267
+ method_table .setclientcert = setclientcert
268
+ method_table .sslhandshake = sslhandshake
121
269
end
122
270
123
271
0 commit comments