Line data Source code
1 :
2 : /*
3 : * Copyright (C) Yichun Zhang (agentzh)
4 : */
5 :
6 :
7 : #ifndef DDEBUG
8 : #define DDEBUG 0
9 : #endif
10 : #include "ddebug.h"
11 :
12 :
13 : #if (NGX_HTTP_SSL)
14 :
15 :
16 : #include "ngx_http_lua_cache.h"
17 : #include "ngx_http_lua_initworkerby.h"
18 : #include "ngx_http_lua_util.h"
19 : #include "ngx_http_ssl_module.h"
20 : #include "ngx_http_lua_contentby.h"
21 : #include "ngx_http_lua_ssl_session_storeby.h"
22 : #include "ngx_http_lua_ssl.h"
23 : #include "ngx_http_lua_directive.h"
24 :
25 :
26 : /* Lua SSL new session store routines */
27 : static u_char *ngx_http_lua_log_ssl_sess_store_error(ngx_log_t *log,
28 : u_char *buf, size_t len);
29 : static ngx_int_t ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L,
30 : ngx_http_request_t *r);
31 :
32 :
33 : /* load Lua code from a file for caching new SSL session. */
34 : ngx_int_t
35 0 : ngx_http_lua_ssl_sess_store_handler_file(ngx_http_request_t *r,
36 : ngx_http_lua_srv_conf_t *lscf, lua_State *L)
37 : {
38 : ngx_int_t rc;
39 :
40 0 : rc = ngx_http_lua_cache_loadfile(r->connection->log, L,
41 0 : lscf->srv.ssl_sess_store_src.data,
42 0 : lscf->srv.ssl_sess_store_src_key);
43 0 : if (rc != NGX_OK) {
44 0 : return rc;
45 : }
46 :
47 : /* make sure we have a valid code chunk */
48 0 : ngx_http_lua_assert(lua_isfunction(L, -1));
49 :
50 0 : return ngx_http_lua_ssl_sess_store_by_chunk(L, r);
51 : }
52 :
53 :
54 : /* load lua code from an inline snippet for caching new SSL session */
55 : ngx_int_t
56 0 : ngx_http_lua_ssl_sess_store_handler_inline(ngx_http_request_t *r,
57 : ngx_http_lua_srv_conf_t *lscf, lua_State *L)
58 : {
59 : ngx_int_t rc;
60 :
61 0 : rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L,
62 0 : lscf->srv.ssl_sess_store_src.data,
63 : lscf->srv.ssl_sess_store_src.len,
64 0 : lscf->srv.ssl_sess_store_src_key,
65 : "=ssl_session_store_by_lua_block");
66 0 : if (rc != NGX_OK) {
67 0 : return rc;
68 : }
69 :
70 : /* make sure we have a valid code chunk */
71 0 : ngx_http_lua_assert(lua_isfunction(L, -1));
72 :
73 0 : return ngx_http_lua_ssl_sess_store_by_chunk(L, r);
74 : }
75 :
76 :
77 : char *
78 0 : ngx_http_lua_ssl_sess_store_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
79 : void *conf)
80 : {
81 : char *rv;
82 : ngx_conf_t save;
83 :
84 0 : save = *cf;
85 0 : cf->handler = ngx_http_lua_ssl_sess_store_by_lua;
86 0 : cf->handler_conf = conf;
87 :
88 0 : rv = ngx_http_lua_conf_lua_block_parse(cf, cmd);
89 :
90 0 : *cf = save;
91 :
92 0 : return rv;
93 : }
94 :
95 :
96 : /* conf parser for directive ssl_session_store_by_lua */
97 : char *
98 0 : ngx_http_lua_ssl_sess_store_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
99 : void *conf)
100 : {
101 : u_char *p;
102 : u_char *name;
103 : ngx_str_t *value;
104 0 : ngx_http_lua_srv_conf_t *lscf = conf;
105 :
106 : dd("enter");
107 :
108 : /* must specify a content handler */
109 0 : if (cmd->post == NULL) {
110 0 : return NGX_CONF_ERROR;
111 : }
112 :
113 0 : if (lscf->srv.ssl_sess_store_handler) {
114 0 : return "is duplicate";
115 : }
116 :
117 0 : if (ngx_http_lua_ssl_init(cf->log) != NGX_OK) {
118 0 : return NGX_CONF_ERROR;
119 : }
120 :
121 0 : value = cf->args->elts;
122 :
123 0 : lscf->srv.ssl_sess_store_handler =
124 0 : (ngx_http_lua_srv_conf_handler_pt) cmd->post;
125 :
126 0 : if (cmd->post == ngx_http_lua_ssl_sess_store_handler_file) {
127 : /* Lua code in an external file */
128 :
129 0 : name = ngx_http_lua_rebase_path(cf->pool, value[1].data,
130 0 : value[1].len);
131 0 : if (name == NULL) {
132 0 : return NGX_CONF_ERROR;
133 : }
134 :
135 0 : lscf->srv.ssl_sess_store_src.data = name;
136 0 : lscf->srv.ssl_sess_store_src.len = ngx_strlen(name);
137 :
138 0 : p = ngx_palloc(cf->pool, NGX_HTTP_LUA_FILE_KEY_LEN + 1);
139 0 : if (p == NULL) {
140 0 : return NGX_CONF_ERROR;
141 : }
142 :
143 0 : lscf->srv.ssl_sess_store_src_key = p;
144 :
145 0 : p = ngx_copy(p, NGX_HTTP_LUA_FILE_TAG, NGX_HTTP_LUA_FILE_TAG_LEN);
146 0 : p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len);
147 0 : *p = '\0';
148 :
149 : } else {
150 : /* inlined Lua code */
151 :
152 0 : lscf->srv.ssl_sess_store_src = value[1];
153 :
154 0 : p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1);
155 0 : if (p == NULL) {
156 0 : return NGX_CONF_ERROR;
157 : }
158 :
159 0 : lscf->srv.ssl_sess_store_src_key = p;
160 :
161 0 : p = ngx_copy(p, NGX_HTTP_LUA_INLINE_TAG, NGX_HTTP_LUA_INLINE_TAG_LEN);
162 0 : p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len);
163 0 : *p = '\0';
164 : }
165 :
166 0 : return NGX_CONF_OK;
167 : }
168 :
169 :
170 : /* callback for new session caching, to be set with SSL_CTX_sess_set_new_cb */
171 : int
172 0 : ngx_http_lua_ssl_sess_store_handler(ngx_ssl_conn_t *ssl_conn,
173 : ngx_ssl_session_t *sess)
174 : {
175 : lua_State *L;
176 : ngx_int_t rc;
177 0 : ngx_connection_t *c, *fc = NULL;
178 0 : ngx_http_request_t *r = NULL;
179 : ngx_http_connection_t *hc;
180 : ngx_http_lua_ssl_ctx_t *cctx;
181 : ngx_http_lua_srv_conf_t *lscf;
182 : ngx_http_core_loc_conf_t *clcf;
183 :
184 0 : c = ngx_ssl_get_connection(ssl_conn);
185 :
186 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
187 : "ssl session store: connection reusable: %ud", c->reusable);
188 :
189 0 : cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection);
190 :
191 : dd("ssl sess_store handler, sess_store-ctx=%p", cctx);
192 :
193 0 : hc = c->data;
194 :
195 0 : fc = ngx_http_lua_create_fake_connection(NULL);
196 0 : if (fc == NULL) {
197 0 : goto failed;
198 : }
199 :
200 0 : fc->log->handler = ngx_http_lua_log_ssl_sess_store_error;
201 0 : fc->log->data = fc;
202 :
203 0 : fc->addr_text = c->addr_text;
204 0 : fc->listening = c->listening;
205 :
206 0 : r = ngx_http_lua_create_fake_request(fc);
207 0 : if (r == NULL) {
208 0 : goto failed;
209 : }
210 :
211 0 : r->main_conf = hc->conf_ctx->main_conf;
212 0 : r->srv_conf = hc->conf_ctx->srv_conf;
213 0 : r->loc_conf = hc->conf_ctx->loc_conf;
214 :
215 0 : fc->log->file = c->log->file;
216 0 : fc->log->log_level = c->log->log_level;
217 0 : fc->ssl = c->ssl;
218 :
219 0 : clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
220 :
221 : #if defined(nginx_version) && nginx_version >= 1003014
222 :
223 : # if nginx_version >= 1009000
224 :
225 0 : ngx_set_connection_log(fc, clcf->error_log);
226 :
227 : # else
228 :
229 : ngx_http_set_connection_log(fc, clcf->error_log);
230 :
231 : # endif
232 :
233 : #else
234 :
235 : fc->log->file = clcf->error_log->file;
236 :
237 : if (!(fc->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
238 : fc->log->log_level = clcf->error_log->log_level;
239 : }
240 :
241 : #endif
242 :
243 0 : if (cctx == NULL) {
244 0 : cctx = ngx_pcalloc(c->pool, sizeof(ngx_http_lua_ssl_ctx_t));
245 0 : if (cctx == NULL) {
246 0 : goto failed; /* error */
247 : }
248 : }
249 :
250 0 : cctx->connection = c;
251 0 : cctx->request = r;
252 0 : cctx->session = sess;
253 0 : cctx->session_id.data = sess->session_id;
254 0 : cctx->session_id.len = sess->session_id_length;
255 0 : cctx->done = 0;
256 :
257 : dd("setting cctx");
258 :
259 0 : if (SSL_set_ex_data(c->ssl->connection, ngx_http_lua_ssl_ctx_index, cctx)
260 : == 0)
261 : {
262 0 : ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed");
263 0 : goto failed;
264 : }
265 :
266 0 : lscf = ngx_http_get_module_srv_conf(r, ngx_http_lua_module);
267 :
268 : /* TODO honor lua_code_cache off */
269 0 : L = ngx_http_lua_get_lua_vm(r, NULL);
270 :
271 0 : c->log->action = "storing SSL session by lua";
272 :
273 0 : rc = lscf->srv.ssl_sess_store_handler(r, lscf, L);
274 :
275 0 : if (rc >= NGX_OK || rc == NGX_ERROR) {
276 0 : cctx->done = 1;
277 :
278 0 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
279 : "ssl_session_store_by_lua*: handler return value: %i, "
280 : "sess new cb exit code: %d", rc, cctx->exit_code);
281 :
282 0 : c->log->action = "SSL handshaking";
283 :
284 : /* Return value is a flag indicating whether the passed-in session
285 : * has been freed by this callback; always return 0 so OpenSSL will
286 : * free the session. Nginx's own session caching logic has the same
287 : * practice. */
288 0 : return 0;
289 : }
290 :
291 : /* impossible to reach here */
292 0 : ngx_http_lua_assert(0);
293 :
294 0 : failed:
295 :
296 0 : if (r && r->pool) {
297 0 : ngx_http_lua_free_fake_request(r);
298 : }
299 :
300 0 : if (fc) {
301 0 : ngx_http_lua_close_fake_connection(fc);
302 : }
303 :
304 0 : return 0;
305 : }
306 :
307 :
308 : static u_char *
309 0 : ngx_http_lua_log_ssl_sess_store_error(ngx_log_t *log, u_char *buf, size_t len)
310 : {
311 : u_char *p;
312 : ngx_connection_t *c;
313 :
314 0 : if (log->action) {
315 0 : p = ngx_snprintf(buf, len, " while %s", log->action);
316 0 : len -= p - buf;
317 0 : buf = p;
318 : }
319 :
320 0 : p = ngx_snprintf(buf, len, ", context: ssl_session_store_by_lua*");
321 0 : len -= p - buf;
322 0 : buf = p;
323 :
324 0 : c = log->data;
325 :
326 0 : if (c->addr_text.len) {
327 0 : p = ngx_snprintf(buf, len, ", client: %V", &c->addr_text);
328 0 : len -= p - buf;
329 0 : buf = p;
330 : }
331 :
332 0 : if (c && c->listening && c->listening->addr_text.len) {
333 0 : p = ngx_snprintf(buf, len, ", server: %V", &c->listening->addr_text);
334 0 : buf = p;
335 : }
336 :
337 0 : return buf;
338 : }
339 :
340 :
341 : /* initialize lua coroutine for caching new SSL session */
342 : static ngx_int_t
343 0 : ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r)
344 : {
345 : size_t len;
346 : u_char *err_msg;
347 : ngx_int_t rc;
348 : ngx_http_lua_ctx_t *ctx;
349 :
350 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
351 :
352 0 : if (ctx == NULL) {
353 0 : ctx = ngx_http_lua_create_ctx(r);
354 0 : if (ctx == NULL) {
355 0 : rc = NGX_ERROR;
356 0 : ngx_http_lua_finalize_request(r, rc);
357 0 : return rc;
358 : }
359 :
360 : } else {
361 : dd("reset ctx");
362 0 : ngx_http_lua_reset_ctx(r, L, ctx);
363 : }
364 :
365 0 : ctx->entered_content_phase = 1;
366 0 : ctx->context = NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE;
367 :
368 : /* init nginx context in Lua VM */
369 0 : ngx_http_lua_set_req(L, r);
370 0 : ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */);
371 :
372 : /* {{{ make new env inheriting main thread's globals table */
373 0 : lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new env */
374 0 : ngx_http_lua_get_globals_table(L);
375 0 : lua_setfield(L, -2, "__index");
376 0 : lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */
377 : /* }}} */
378 :
379 0 : lua_setfenv(L, -2); /* set new running env for the code closure */
380 :
381 0 : lua_pushcfunction(L, ngx_http_lua_traceback);
382 0 : lua_insert(L, 1); /* put it under chunk and args */
383 :
384 : /* protected call user code */
385 0 : rc = lua_pcall(L, 0, 1, 1);
386 :
387 0 : lua_remove(L, 1); /* remove traceback function */
388 :
389 : dd("rc == %d", (int) rc);
390 :
391 0 : if (rc != 0) {
392 : /* error occurred when running loaded code */
393 0 : err_msg = (u_char *) lua_tolstring(L, -1, &len);
394 :
395 0 : if (err_msg == NULL) {
396 0 : err_msg = (u_char *) "unknown reason";
397 0 : len = sizeof("unknown reason") - 1;
398 : }
399 :
400 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
401 : "failed to run session_store_by_lua*: %*s", len, err_msg);
402 :
403 0 : lua_settop(L, 0); /* clear remaining elems on stack */
404 0 : ngx_http_lua_finalize_request(r, rc);
405 :
406 0 : return NGX_ERROR;
407 : }
408 :
409 0 : lua_settop(L, 0); /* clear remaining elems on stack */
410 0 : ngx_http_lua_finalize_request(r, rc);
411 0 : return rc;
412 : }
413 :
414 :
415 : #ifndef NGX_LUA_NO_FFI_API
416 :
417 : /* serialize a session from lua context into buf.
418 : * the memory allocation of buf should be handled externally. */
419 : int
420 0 : ngx_http_lua_ffi_ssl_get_serialized_session(ngx_http_request_t *r,
421 : u_char *buf, char **err)
422 : {
423 : ngx_ssl_conn_t *ssl_conn;
424 : ngx_connection_t *c;
425 : ngx_ssl_session_t *session;
426 : ngx_http_lua_ssl_ctx_t *cctx;
427 :
428 0 : c = r->connection;
429 :
430 0 : if (c == NULL || c->ssl == NULL) {
431 0 : *err = "bad request";
432 0 : return NGX_ERROR;
433 : }
434 :
435 0 : ssl_conn = c->ssl->connection;
436 0 : if (ssl_conn == NULL) {
437 0 : *err = "bad ssl conn";
438 0 : return NGX_ERROR;
439 : }
440 :
441 : dd("get cctx session");
442 :
443 0 : cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection);
444 0 : if (cctx == NULL) {
445 0 : *err = "bad lua context";
446 0 : return NGX_ERROR;
447 : }
448 :
449 0 : session = cctx->session;
450 0 : if (session == NULL) {
451 0 : *err = "bad session in lua context";
452 0 : return NGX_ERROR;
453 : }
454 :
455 0 : if (i2d_SSL_SESSION(session, &buf) == 0) {
456 0 : *err = "i2d_SSL_SESSION() failed";
457 0 : return NGX_ERROR;
458 : }
459 :
460 0 : return NGX_OK;
461 : }
462 :
463 :
464 : /* return the size of serialized session. */
465 : int
466 0 : ngx_http_lua_ffi_ssl_get_serialized_session_size(ngx_http_request_t *r,
467 : char **err)
468 : {
469 : int len;
470 : ngx_ssl_conn_t *ssl_conn;
471 : ngx_connection_t *c;
472 : ngx_ssl_session_t *session;
473 : ngx_http_lua_ssl_ctx_t *cctx;
474 :
475 0 : c = r->connection;
476 :
477 0 : if (c == NULL || c->ssl == NULL) {
478 0 : *err = "bad request";
479 0 : return NGX_ERROR;
480 : }
481 :
482 0 : ssl_conn = c->ssl->connection;
483 0 : if (ssl_conn == NULL) {
484 0 : *err = "bad ssl conn";
485 0 : return NGX_ERROR;
486 : }
487 :
488 : dd("get cctx session size");
489 0 : cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection);
490 0 : if (cctx == NULL) {
491 0 : *err = "bad lua context";
492 0 : return NGX_ERROR;
493 : }
494 :
495 0 : session = cctx->session;
496 0 : if (session == NULL) {
497 0 : *err = "bad session in lua context";
498 0 : return NGX_ERROR;
499 : }
500 :
501 0 : len = i2d_SSL_SESSION(session, NULL);
502 0 : if (len == 0) {
503 0 : *err = "i2d_SSL_SESSION() failed";
504 0 : return NGX_ERROR;
505 : }
506 :
507 0 : return len;
508 : }
509 :
510 :
511 : /* serialize the session id from lua context into buf.
512 : * the memory allocation of buf should be handled externally. */
513 : int
514 0 : ngx_http_lua_ffi_ssl_get_session_id(ngx_http_request_t *r,
515 : u_char *buf, char **err)
516 : {
517 : int id_len;
518 : u_char *id;
519 : ngx_ssl_conn_t *ssl_conn;
520 : ngx_connection_t *c;
521 : ngx_http_lua_ssl_ctx_t *cctx;
522 :
523 0 : c = r->connection;
524 :
525 0 : if (c == NULL || c->ssl == NULL) {
526 0 : *err = "bad request";
527 0 : return NGX_ERROR;
528 : }
529 :
530 0 : ssl_conn = c->ssl->connection;
531 0 : if (ssl_conn == NULL) {
532 0 : *err = "bad ssl conn";
533 0 : return NGX_ERROR;
534 : }
535 :
536 : dd("get cctx session");
537 0 : cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection);
538 0 : if (cctx == NULL) {
539 0 : *err = "bad lua context";
540 0 : return NGX_ERROR;
541 : }
542 :
543 0 : id = cctx->session_id.data;
544 0 : if (id == NULL) {
545 0 : *err = "uninitialized session id in lua context";
546 0 : return NGX_ERROR;
547 : }
548 :
549 0 : id_len = cctx->session_id.len;
550 0 : if (id_len == 0) {
551 0 : *err = "uninitialized session id len in lua context";
552 0 : return NGX_ERROR;
553 : }
554 :
555 0 : ngx_hex_dump(buf, id, id_len);
556 :
557 0 : return NGX_OK;
558 : }
559 :
560 :
561 : /* return the size of serialized session id. */
562 : int
563 0 : ngx_http_lua_ffi_ssl_get_session_id_size(ngx_http_request_t *r,
564 : char **err)
565 : {
566 : ngx_ssl_conn_t *ssl_conn;
567 : ngx_connection_t *c;
568 : ngx_http_lua_ssl_ctx_t *cctx;
569 :
570 0 : c = r->connection;
571 :
572 0 : if (c == NULL || c->ssl == NULL) {
573 0 : *err = "bad request";
574 0 : return NGX_ERROR;
575 : }
576 :
577 0 : ssl_conn = c->ssl->connection;
578 0 : if (ssl_conn == NULL) {
579 0 : *err = "bad ssl conn";
580 0 : return NGX_ERROR;
581 : }
582 :
583 : dd("get cctx session");
584 0 : cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection);
585 0 : if (cctx == NULL) {
586 0 : *err = "bad lua context";
587 0 : return NGX_ERROR;
588 : }
589 :
590 0 : if (cctx->session_id.len == 0) {
591 0 : *err = "uninitialized session id len in lua context";
592 0 : return NGX_ERROR;
593 : }
594 :
595 : /* since the session id will be hex dumped to serialize, the serialized
596 : * session will be twice the size of the session id: each byte will be a
597 : * 2-digit hex value. */
598 :
599 0 : return 2 * cctx->session_id.len;
600 : }
601 :
602 : #endif /* NGX_LUA_NO_FFI_API */
603 :
604 :
605 : #endif /* NGX_HTTP_SSL */
|