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_certby.h"
22 : #include "ngx_http_lua_directive.h"
23 : #include "ngx_http_lua_ssl.h"
24 :
25 :
26 : enum {
27 : NGX_HTTP_LUA_ADDR_TYPE_UNIX = 0,
28 : NGX_HTTP_LUA_ADDR_TYPE_INET = 1,
29 : NGX_HTTP_LUA_ADDR_TYPE_INET6 = 2
30 : };
31 :
32 :
33 : static void ngx_http_lua_ssl_cert_done(void *data);
34 : static void ngx_http_lua_ssl_cert_aborted(void *data);
35 : static u_char *ngx_http_lua_log_ssl_cert_error(ngx_log_t *log, u_char *buf,
36 : size_t len);
37 : static ngx_int_t ngx_http_lua_ssl_cert_by_chunk(lua_State *L,
38 : ngx_http_request_t *r);
39 :
40 :
41 : ngx_int_t
42 0 : ngx_http_lua_ssl_cert_handler_file(ngx_http_request_t *r,
43 : ngx_http_lua_srv_conf_t *lscf, lua_State *L)
44 : {
45 : ngx_int_t rc;
46 :
47 0 : rc = ngx_http_lua_cache_loadfile(r->connection->log, L,
48 0 : lscf->srv.ssl_cert_src.data,
49 0 : lscf->srv.ssl_cert_src_key);
50 0 : if (rc != NGX_OK) {
51 0 : return rc;
52 : }
53 :
54 : /* make sure we have a valid code chunk */
55 0 : ngx_http_lua_assert(lua_isfunction(L, -1));
56 :
57 0 : return ngx_http_lua_ssl_cert_by_chunk(L, r);
58 : }
59 :
60 :
61 : ngx_int_t
62 0 : ngx_http_lua_ssl_cert_handler_inline(ngx_http_request_t *r,
63 : ngx_http_lua_srv_conf_t *lscf, lua_State *L)
64 : {
65 : ngx_int_t rc;
66 :
67 0 : rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L,
68 0 : lscf->srv.ssl_cert_src.data,
69 : lscf->srv.ssl_cert_src.len,
70 0 : lscf->srv.ssl_cert_src_key,
71 : "=ssl_certificate_by_lua");
72 0 : if (rc != NGX_OK) {
73 0 : return rc;
74 : }
75 :
76 : /* make sure we have a valid code chunk */
77 0 : ngx_http_lua_assert(lua_isfunction(L, -1));
78 :
79 0 : return ngx_http_lua_ssl_cert_by_chunk(L, r);
80 : }
81 :
82 :
83 : char *
84 0 : ngx_http_lua_ssl_cert_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
85 : void *conf)
86 : {
87 : char *rv;
88 : ngx_conf_t save;
89 :
90 0 : save = *cf;
91 0 : cf->handler = ngx_http_lua_ssl_cert_by_lua;
92 0 : cf->handler_conf = conf;
93 :
94 0 : rv = ngx_http_lua_conf_lua_block_parse(cf, cmd);
95 :
96 0 : *cf = save;
97 :
98 0 : return rv;
99 : }
100 :
101 :
102 : char *
103 0 : ngx_http_lua_ssl_cert_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
104 : void *conf)
105 : {
106 : #if OPENSSL_VERSION_NUMBER < 0x1000205fL
107 :
108 : ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
109 : "at least OpenSSL 1.0.2e required but found "
110 : OPENSSL_VERSION_TEXT);
111 :
112 : return NGX_CONF_ERROR;
113 :
114 : #else
115 :
116 : u_char *p;
117 : u_char *name;
118 : ngx_str_t *value;
119 0 : ngx_http_lua_srv_conf_t *lscf = conf;
120 :
121 : /* must specify a concrete handler */
122 0 : if (cmd->post == NULL) {
123 0 : return NGX_CONF_ERROR;
124 : }
125 :
126 0 : if (lscf->srv.ssl_cert_handler) {
127 0 : return "is duplicate";
128 : }
129 :
130 0 : if (ngx_http_lua_ssl_init(cf->log) != NGX_OK) {
131 0 : return NGX_CONF_ERROR;
132 : }
133 :
134 0 : value = cf->args->elts;
135 :
136 0 : lscf->srv.ssl_cert_handler = (ngx_http_lua_srv_conf_handler_pt) cmd->post;
137 :
138 0 : if (cmd->post == ngx_http_lua_ssl_cert_handler_file) {
139 : /* Lua code in an external file */
140 :
141 0 : name = ngx_http_lua_rebase_path(cf->pool, value[1].data,
142 0 : value[1].len);
143 0 : if (name == NULL) {
144 0 : return NGX_CONF_ERROR;
145 : }
146 :
147 0 : lscf->srv.ssl_cert_src.data = name;
148 0 : lscf->srv.ssl_cert_src.len = ngx_strlen(name);
149 :
150 0 : p = ngx_palloc(cf->pool, NGX_HTTP_LUA_FILE_KEY_LEN + 1);
151 0 : if (p == NULL) {
152 0 : return NGX_CONF_ERROR;
153 : }
154 :
155 0 : lscf->srv.ssl_cert_src_key = p;
156 :
157 0 : p = ngx_copy(p, NGX_HTTP_LUA_FILE_TAG, NGX_HTTP_LUA_FILE_TAG_LEN);
158 0 : p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len);
159 0 : *p = '\0';
160 :
161 : } else {
162 : /* inlined Lua code */
163 :
164 0 : lscf->srv.ssl_cert_src = value[1];
165 :
166 0 : p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1);
167 0 : if (p == NULL) {
168 0 : return NGX_CONF_ERROR;
169 : }
170 :
171 0 : lscf->srv.ssl_cert_src_key = p;
172 :
173 0 : p = ngx_copy(p, NGX_HTTP_LUA_INLINE_TAG, NGX_HTTP_LUA_INLINE_TAG_LEN);
174 0 : p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len);
175 0 : *p = '\0';
176 : }
177 :
178 0 : return NGX_CONF_OK;
179 :
180 : #endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */
181 : }
182 :
183 :
184 : int
185 0 : ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data)
186 : {
187 : lua_State *L;
188 : ngx_int_t rc;
189 : ngx_connection_t *c, *fc;
190 0 : ngx_http_request_t *r = NULL;
191 : ngx_pool_cleanup_t *cln;
192 : ngx_http_connection_t *hc;
193 : ngx_http_lua_srv_conf_t *lscf;
194 : ngx_http_core_loc_conf_t *clcf;
195 : ngx_http_lua_ssl_ctx_t *cctx;
196 : ngx_http_core_srv_conf_t *cscf;
197 :
198 0 : c = ngx_ssl_get_connection(ssl_conn);
199 :
200 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
201 : "ssl cert: connection reusable: %ud", c->reusable);
202 :
203 0 : cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection);
204 :
205 : dd("ssl cert handler, cert-ctx=%p", cctx);
206 :
207 0 : if (cctx && cctx->entered_cert_handler) {
208 : /* not the first time */
209 :
210 0 : if (cctx->done) {
211 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
212 : "lua_certificate_by_lua: cert cb exit code: %d",
213 : cctx->exit_code);
214 :
215 : dd("lua ssl cert done, finally");
216 0 : return cctx->exit_code;
217 : }
218 :
219 0 : return -1;
220 : }
221 :
222 : dd("first time");
223 :
224 0 : ngx_reusable_connection(c, 0);
225 :
226 0 : hc = c->data;
227 :
228 0 : fc = ngx_http_lua_create_fake_connection(NULL);
229 0 : if (fc == NULL) {
230 0 : goto failed;
231 : }
232 :
233 0 : fc->log->handler = ngx_http_lua_log_ssl_cert_error;
234 0 : fc->log->data = fc;
235 :
236 0 : fc->addr_text = c->addr_text;
237 0 : fc->listening = c->listening;
238 :
239 0 : r = ngx_http_lua_create_fake_request(fc);
240 0 : if (r == NULL) {
241 0 : goto failed;
242 : }
243 :
244 0 : r->main_conf = hc->conf_ctx->main_conf;
245 0 : r->srv_conf = hc->conf_ctx->srv_conf;
246 0 : r->loc_conf = hc->conf_ctx->loc_conf;
247 :
248 0 : fc->log->file = c->log->file;
249 0 : fc->log->log_level = c->log->log_level;
250 0 : fc->ssl = c->ssl;
251 :
252 0 : clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
253 :
254 : #if defined(nginx_version) && nginx_version >= 1003014
255 :
256 : # if nginx_version >= 1009000
257 :
258 0 : ngx_set_connection_log(fc, clcf->error_log);
259 :
260 : # else
261 :
262 : ngx_http_set_connection_log(fc, clcf->error_log);
263 :
264 : # endif
265 :
266 : #else
267 :
268 : fc->log->file = clcf->error_log->file;
269 :
270 : if (!(fc->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
271 : fc->log->log_level = clcf->error_log->log_level;
272 : }
273 :
274 : #endif
275 :
276 0 : if (cctx == NULL) {
277 0 : cctx = ngx_pcalloc(c->pool, sizeof(ngx_http_lua_ssl_ctx_t));
278 0 : if (cctx == NULL) {
279 0 : goto failed; /* error */
280 : }
281 : }
282 :
283 0 : cctx->exit_code = 1; /* successful by default */
284 0 : cctx->connection = c;
285 0 : cctx->request = r;
286 0 : cctx->entered_cert_handler = 1;
287 0 : cctx->done = 0;
288 :
289 : dd("setting cctx");
290 :
291 0 : if (SSL_set_ex_data(c->ssl->connection, ngx_http_lua_ssl_ctx_index, cctx)
292 : == 0)
293 : {
294 0 : ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed");
295 0 : goto failed;
296 : }
297 :
298 0 : lscf = ngx_http_get_module_srv_conf(r, ngx_http_lua_module);
299 :
300 : /* TODO honor lua_code_cache off */
301 0 : L = ngx_http_lua_get_lua_vm(r, NULL);
302 :
303 0 : c->log->action = "loading SSL certificate by lua";
304 :
305 0 : if (lscf->srv.ssl_cert_handler == NULL) {
306 0 : cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
307 :
308 0 : ngx_log_error(NGX_LOG_ALERT, c->log, 0,
309 : "no ssl_certificate_by_lua* defined in "
310 : "server %V", &cscf->server_name);
311 :
312 0 : goto failed;
313 : }
314 :
315 0 : rc = lscf->srv.ssl_cert_handler(r, lscf, L);
316 :
317 0 : if (rc >= NGX_OK || rc == NGX_ERROR) {
318 0 : cctx->done = 1;
319 :
320 0 : if (cctx->cleanup) {
321 0 : *cctx->cleanup = NULL;
322 : }
323 :
324 0 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
325 : "lua_certificate_by_lua: handler return value: %i, "
326 : "cert cb exit code: %d", rc, cctx->exit_code);
327 :
328 0 : c->log->action = "SSL handshaking";
329 0 : return cctx->exit_code;
330 : }
331 :
332 : /* rc == NGX_DONE */
333 :
334 0 : cln = ngx_pool_cleanup_add(fc->pool, 0);
335 0 : if (cln == NULL) {
336 0 : goto failed;
337 : }
338 :
339 0 : cln->handler = ngx_http_lua_ssl_cert_done;
340 0 : cln->data = cctx;
341 :
342 0 : if (cctx->cleanup == NULL) {
343 0 : cln = ngx_pool_cleanup_add(c->pool, 0);
344 0 : if (cln == NULL) {
345 0 : goto failed;
346 : }
347 :
348 0 : cln->data = cctx;
349 0 : cctx->cleanup = &cln->handler;
350 : }
351 :
352 0 : *cctx->cleanup = ngx_http_lua_ssl_cert_aborted;
353 :
354 0 : return -1;
355 :
356 : #if 1
357 0 : failed:
358 :
359 0 : if (r && r->pool) {
360 0 : ngx_http_lua_free_fake_request(r);
361 : }
362 :
363 0 : if (fc) {
364 0 : ngx_http_lua_close_fake_connection(fc);
365 : }
366 :
367 0 : return 0;
368 : #endif
369 : }
370 :
371 :
372 : static void
373 0 : ngx_http_lua_ssl_cert_done(void *data)
374 : {
375 : ngx_connection_t *c;
376 0 : ngx_http_lua_ssl_ctx_t *cctx = data;
377 :
378 : dd("lua ssl cert done");
379 :
380 0 : if (cctx->aborted) {
381 0 : return;
382 : }
383 :
384 0 : ngx_http_lua_assert(cctx->done == 0);
385 :
386 0 : cctx->done = 1;
387 :
388 0 : if (cctx->cleanup) {
389 0 : *cctx->cleanup = NULL;
390 : }
391 :
392 0 : c = cctx->connection;
393 :
394 0 : c->log->action = "SSL handshaking";
395 :
396 0 : ngx_post_event(c->write, &ngx_posted_events);
397 : }
398 :
399 :
400 : static void
401 0 : ngx_http_lua_ssl_cert_aborted(void *data)
402 : {
403 0 : ngx_http_lua_ssl_ctx_t *cctx = data;
404 :
405 : dd("lua ssl cert done");
406 :
407 0 : if (cctx->done) {
408 : /* completed successfully already */
409 0 : return;
410 : }
411 :
412 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cctx->connection->log, 0,
413 : "lua_certificate_by_lua: cert cb aborted");
414 :
415 0 : cctx->aborted = 1;
416 0 : cctx->request->connection->ssl = NULL;
417 :
418 0 : ngx_http_lua_finalize_fake_request(cctx->request, NGX_ERROR);
419 : }
420 :
421 :
422 : static u_char *
423 0 : ngx_http_lua_log_ssl_cert_error(ngx_log_t *log, u_char *buf, size_t len)
424 : {
425 : u_char *p;
426 : ngx_connection_t *c;
427 :
428 0 : if (log->action) {
429 0 : p = ngx_snprintf(buf, len, " while %s", log->action);
430 0 : len -= p - buf;
431 0 : buf = p;
432 : }
433 :
434 0 : p = ngx_snprintf(buf, len, ", context: ssl_certificate_by_lua*");
435 0 : len -= p - buf;
436 0 : buf = p;
437 :
438 0 : c = log->data;
439 :
440 0 : if (c->addr_text.len) {
441 0 : p = ngx_snprintf(buf, len, ", client: %V", &c->addr_text);
442 0 : len -= p - buf;
443 0 : buf = p;
444 : }
445 :
446 0 : if (c && c->listening && c->listening->addr_text.len) {
447 0 : p = ngx_snprintf(buf, len, ", server: %V", &c->listening->addr_text);
448 : /* len -= p - buf; */
449 0 : buf = p;
450 : }
451 :
452 0 : return buf;
453 : }
454 :
455 :
456 : static ngx_int_t
457 0 : ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r)
458 : {
459 : int co_ref;
460 : ngx_int_t rc;
461 : lua_State *co;
462 : ngx_http_lua_ctx_t *ctx;
463 : ngx_http_cleanup_t *cln;
464 :
465 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
466 :
467 0 : if (ctx == NULL) {
468 0 : ctx = ngx_http_lua_create_ctx(r);
469 0 : if (ctx == NULL) {
470 0 : rc = NGX_ERROR;
471 0 : ngx_http_lua_finalize_request(r, rc);
472 0 : return rc;
473 : }
474 :
475 : } else {
476 : dd("reset ctx");
477 0 : ngx_http_lua_reset_ctx(r, L, ctx);
478 : }
479 :
480 0 : ctx->entered_content_phase = 1;
481 :
482 : /* {{{ new coroutine to handle request */
483 0 : co = ngx_http_lua_new_thread(r, L, &co_ref);
484 :
485 0 : if (co == NULL) {
486 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
487 : "lua: failed to create new coroutine to handle request");
488 :
489 0 : rc = NGX_ERROR;
490 0 : ngx_http_lua_finalize_request(r, rc);
491 0 : return rc;
492 : }
493 :
494 : /* move code closure to new coroutine */
495 0 : lua_xmove(L, co, 1);
496 :
497 : /* set closure's env table to new coroutine's globals table */
498 0 : ngx_http_lua_get_globals_table(co);
499 0 : lua_setfenv(co, -2);
500 :
501 : /* save nginx request in coroutine globals table */
502 0 : ngx_http_lua_set_req(co, r);
503 :
504 0 : ctx->cur_co_ctx = &ctx->entry_co_ctx;
505 0 : ctx->cur_co_ctx->co = co;
506 0 : ctx->cur_co_ctx->co_ref = co_ref;
507 : #ifdef NGX_LUA_USE_ASSERT
508 0 : ctx->cur_co_ctx->co_top = 1;
509 : #endif
510 :
511 : /* register request cleanup hooks */
512 0 : if (ctx->cleanup == NULL) {
513 0 : cln = ngx_http_cleanup_add(r, 0);
514 0 : if (cln == NULL) {
515 0 : rc = NGX_ERROR;
516 0 : ngx_http_lua_finalize_request(r, rc);
517 0 : return rc;
518 : }
519 :
520 0 : cln->handler = ngx_http_lua_request_cleanup_handler;
521 0 : cln->data = ctx;
522 0 : ctx->cleanup = &cln->handler;
523 : }
524 :
525 0 : ctx->context = NGX_HTTP_LUA_CONTEXT_SSL_CERT;
526 :
527 0 : rc = ngx_http_lua_run_thread(L, r, ctx, 0);
528 :
529 0 : if (rc == NGX_ERROR || rc >= NGX_OK) {
530 : /* do nothing */
531 :
532 0 : } else if (rc == NGX_AGAIN) {
533 0 : rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 0);
534 :
535 0 : } else if (rc == NGX_DONE) {
536 0 : rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 1);
537 :
538 : } else {
539 0 : rc = NGX_OK;
540 : }
541 :
542 0 : ngx_http_lua_finalize_request(r, rc);
543 0 : return rc;
544 : }
545 :
546 :
547 : #ifndef NGX_LUA_NO_FFI_API
548 :
549 : int
550 0 : ngx_http_lua_ffi_ssl_get_tls1_version(ngx_http_request_t *r, char **err)
551 : {
552 : #ifndef TLS1_get_version
553 :
554 : *err = "no TLS1 support";
555 : return NGX_ERROR;
556 :
557 : #else
558 :
559 : ngx_ssl_conn_t *ssl_conn;
560 :
561 0 : if (r->connection == NULL || r->connection->ssl == NULL) {
562 0 : *err = "bad request";
563 0 : return NGX_ERROR;
564 : }
565 :
566 0 : ssl_conn = r->connection->ssl->connection;
567 0 : if (ssl_conn == NULL) {
568 0 : *err = "bad ssl conn";
569 0 : return NGX_ERROR;
570 : }
571 :
572 : dd("tls1 ver: %d", (int) TLS1_get_version(ssl_conn));
573 :
574 0 : return (int) TLS1_get_version(ssl_conn);
575 :
576 : #endif
577 : }
578 :
579 :
580 : int
581 0 : ngx_http_lua_ffi_ssl_clear_certs(ngx_http_request_t *r, char **err)
582 : {
583 : #ifdef LIBRESSL_VERSION_NUMBER
584 :
585 : *err = "LibreSSL not supported";
586 : return NGX_ERROR;
587 :
588 : #else
589 :
590 : # if OPENSSL_VERSION_NUMBER < 0x1000205fL
591 :
592 : *err = "at least OpenSSL 1.0.2e required but found " OPENSSL_VERSION_TEXT;
593 : return NGX_ERROR;
594 :
595 : # else
596 :
597 : ngx_ssl_conn_t *ssl_conn;
598 :
599 0 : if (r->connection == NULL || r->connection->ssl == NULL) {
600 0 : *err = "bad request";
601 0 : return NGX_ERROR;
602 : }
603 :
604 0 : ssl_conn = r->connection->ssl->connection;
605 0 : if (ssl_conn == NULL) {
606 0 : *err = "bad ssl conn";
607 0 : return NGX_ERROR;
608 : }
609 :
610 0 : SSL_certs_clear(ssl_conn);
611 0 : return NGX_OK;
612 :
613 : # endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */
614 : #endif
615 : }
616 :
617 :
618 : int
619 0 : ngx_http_lua_ffi_ssl_set_der_certificate(ngx_http_request_t *r,
620 : const char *data, size_t len, char **err)
621 : {
622 : #ifdef LIBRESSL_VERSION_NUMBER
623 :
624 : *err = "LibreSSL not supported";
625 : return NGX_ERROR;
626 :
627 : #else
628 :
629 : # if OPENSSL_VERSION_NUMBER < 0x1000205fL
630 :
631 : *err = "at least OpenSSL 1.0.2e required but found " OPENSSL_VERSION_TEXT;
632 : return NGX_ERROR;
633 :
634 : # else
635 :
636 0 : BIO *bio = NULL;
637 0 : X509 *x509 = NULL;
638 : ngx_ssl_conn_t *ssl_conn;
639 :
640 0 : if (r->connection == NULL || r->connection->ssl == NULL) {
641 0 : *err = "bad request";
642 0 : return NGX_ERROR;
643 : }
644 :
645 0 : ssl_conn = r->connection->ssl->connection;
646 0 : if (ssl_conn == NULL) {
647 0 : *err = "bad ssl conn";
648 0 : return NGX_ERROR;
649 : }
650 :
651 0 : bio = BIO_new_mem_buf((char *) data, len);
652 0 : if (bio == NULL) {
653 0 : *err = "BIO_new_mem_buf() failed";
654 0 : goto failed;
655 : }
656 :
657 0 : x509 = d2i_X509_bio(bio, NULL);
658 0 : if (x509 == NULL) {
659 0 : *err = "d2i_X509_bio() failed";
660 0 : goto failed;
661 : }
662 :
663 0 : if (SSL_use_certificate(ssl_conn, x509) == 0) {
664 0 : *err = "SSL_use_certificate() failed";
665 0 : goto failed;
666 : }
667 :
668 : #if 0
669 : if (SSL_set_ex_data(ssl_conn, ngx_ssl_certificate_index, x509) == 0) {
670 : *err = "SSL_set_ex_data() failed";
671 : goto failed;
672 : }
673 : #endif
674 :
675 0 : X509_free(x509);
676 0 : x509 = NULL;
677 :
678 : /* read rest of the chain */
679 :
680 0 : while (!BIO_eof(bio)) {
681 :
682 0 : x509 = d2i_X509_bio(bio, NULL);
683 0 : if (x509 == NULL) {
684 0 : *err = "d2i_X509_bio() failed";
685 0 : goto failed;
686 : }
687 :
688 0 : if (SSL_add0_chain_cert(ssl_conn, x509) == 0) {
689 0 : *err = "SSL_add0_chain_cert() failed";
690 0 : goto failed;
691 : }
692 : }
693 :
694 0 : BIO_free(bio);
695 :
696 0 : *err = NULL;
697 0 : return NGX_OK;
698 :
699 0 : failed:
700 :
701 0 : if (bio) {
702 0 : BIO_free(bio);
703 : }
704 :
705 0 : if (x509) {
706 0 : X509_free(x509);
707 : }
708 :
709 0 : ERR_clear_error();
710 :
711 0 : return NGX_ERROR;
712 :
713 : # endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */
714 : #endif
715 : }
716 :
717 :
718 : int
719 0 : ngx_http_lua_ffi_ssl_set_der_private_key(ngx_http_request_t *r,
720 : const char *data, size_t len, char **err)
721 : {
722 0 : BIO *bio = NULL;
723 0 : EVP_PKEY *pkey = NULL;
724 : ngx_ssl_conn_t *ssl_conn;
725 :
726 0 : if (r->connection == NULL || r->connection->ssl == NULL) {
727 0 : *err = "bad request";
728 0 : return NGX_ERROR;
729 : }
730 :
731 0 : ssl_conn = r->connection->ssl->connection;
732 0 : if (ssl_conn == NULL) {
733 0 : *err = "bad ssl conn";
734 0 : return NGX_ERROR;
735 : }
736 :
737 0 : bio = BIO_new_mem_buf((char *) data, len);
738 0 : if (bio == NULL) {
739 0 : *err = "BIO_new_mem_buf() failed";
740 0 : goto failed;
741 : }
742 :
743 0 : pkey = d2i_PrivateKey_bio(bio, NULL);
744 0 : if (pkey == NULL) {
745 0 : *err = "d2i_PrivateKey_bio() failed";
746 0 : goto failed;
747 : }
748 :
749 0 : if (SSL_use_PrivateKey(ssl_conn, pkey) == 0) {
750 0 : *err = "SSL_CTX_use_PrivateKey() failed";
751 0 : goto failed;
752 : }
753 :
754 0 : EVP_PKEY_free(pkey);
755 0 : BIO_free(bio);
756 :
757 0 : return NGX_OK;
758 :
759 0 : failed:
760 :
761 0 : if (pkey) {
762 0 : EVP_PKEY_free(pkey);
763 : }
764 :
765 0 : if (bio) {
766 0 : BIO_free(bio);
767 : }
768 :
769 0 : ERR_clear_error();
770 :
771 0 : return NGX_ERROR;
772 : }
773 :
774 :
775 : int
776 0 : ngx_http_lua_ffi_ssl_raw_server_addr(ngx_http_request_t *r, char **addr,
777 : size_t *addrlen, int *addrtype, char **err)
778 : {
779 : #if (NGX_HAVE_UNIX_DOMAIN)
780 : struct sockaddr_un *saun;
781 : #endif
782 : ngx_ssl_conn_t *ssl_conn;
783 : ngx_connection_t *c;
784 : struct sockaddr_in *sin;
785 : #if (NGX_HAVE_INET6)
786 : struct sockaddr_in6 *sin6;
787 : #endif
788 :
789 0 : if (r->connection == NULL || r->connection->ssl == NULL) {
790 0 : *err = "bad request";
791 0 : return NGX_ERROR;
792 : }
793 :
794 0 : ssl_conn = r->connection->ssl->connection;
795 0 : if (ssl_conn == NULL) {
796 0 : *err = "bad ssl conn";
797 0 : return NGX_ERROR;
798 : }
799 :
800 0 : c = ngx_ssl_get_connection(ssl_conn);
801 :
802 0 : if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
803 0 : return 0;
804 : }
805 :
806 0 : switch (c->local_sockaddr->sa_family) {
807 :
808 : #if (NGX_HAVE_INET6)
809 0 : case AF_INET6:
810 0 : sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
811 0 : *addrlen = 16;
812 0 : *addr = (char *) &sin6->sin6_addr.s6_addr;
813 0 : *addrtype = NGX_HTTP_LUA_ADDR_TYPE_INET6;
814 :
815 0 : break;
816 : #endif
817 :
818 : #if (NGX_HAVE_UNIX_DOMAIN)
819 0 : case AF_UNIX:
820 0 : saun = (struct sockaddr_un *) c->local_sockaddr;
821 :
822 : /* on Linux sockaddr might not include sun_path at all */
823 0 : if (c->local_socklen <= (socklen_t)
824 : offsetof(struct sockaddr_un, sun_path))
825 : {
826 0 : *addr = "";
827 0 : *addrlen = 0;
828 :
829 : } else {
830 0 : *addr = saun->sun_path;
831 0 : *addrlen = ngx_strlen(saun->sun_path);
832 : }
833 :
834 0 : *addrtype = NGX_HTTP_LUA_ADDR_TYPE_UNIX;
835 0 : break;
836 : #endif
837 :
838 0 : default: /* AF_INET */
839 0 : sin = (struct sockaddr_in *) c->local_sockaddr;
840 0 : *addr = (char *) &sin->sin_addr.s_addr;
841 0 : *addrlen = 4;
842 0 : *addrtype = NGX_HTTP_LUA_ADDR_TYPE_INET;
843 0 : break;
844 : }
845 :
846 0 : return NGX_OK;
847 : }
848 :
849 :
850 : int
851 0 : ngx_http_lua_ffi_ssl_server_name(ngx_http_request_t *r, char **name,
852 : size_t *namelen, char **err)
853 : {
854 : ngx_ssl_conn_t *ssl_conn;
855 :
856 0 : if (r->connection == NULL || r->connection->ssl == NULL) {
857 0 : *err = "bad request";
858 0 : return NGX_ERROR;
859 : }
860 :
861 0 : ssl_conn = r->connection->ssl->connection;
862 0 : if (ssl_conn == NULL) {
863 0 : *err = "bad ssl conn";
864 0 : return NGX_ERROR;
865 : }
866 :
867 : #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
868 :
869 0 : *name = (char *) SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name);
870 :
871 0 : if (*name) {
872 0 : *namelen = ngx_strlen(*name);
873 0 : return NGX_OK;
874 : }
875 :
876 0 : return NGX_DECLINED;
877 :
878 : #else
879 :
880 : *err = "no TLS extension support";
881 : return NGX_ERROR;
882 :
883 : #endif
884 : }
885 :
886 :
887 : int
888 0 : ngx_http_lua_ffi_cert_pem_to_der(const u_char *pem, size_t pem_len, u_char *der,
889 : char **err)
890 : {
891 : int total, len;
892 : BIO *bio;
893 : X509 *x509;
894 : u_long n;
895 :
896 0 : bio = BIO_new_mem_buf((char *) pem, (int) pem_len);
897 0 : if (bio == NULL) {
898 0 : *err = "BIO_new_mem_buf() failed";
899 0 : ERR_clear_error();
900 0 : return NGX_ERROR;
901 : }
902 :
903 0 : x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
904 0 : if (x509 == NULL) {
905 0 : *err = "PEM_read_bio_X509_AUX() failed";
906 0 : BIO_free(bio);
907 0 : ERR_clear_error();
908 0 : return NGX_ERROR;
909 : }
910 :
911 0 : total = i2d_X509(x509, &der);
912 0 : if (total < 0) {
913 0 : *err = "i2d_X509() failed";
914 0 : X509_free(x509);
915 0 : BIO_free(bio);
916 0 : ERR_clear_error();
917 0 : return NGX_ERROR;
918 : }
919 :
920 0 : X509_free(x509);
921 :
922 : /* read rest of the chain */
923 :
924 : for ( ;; ) {
925 :
926 0 : x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
927 0 : if (x509 == NULL) {
928 0 : n = ERR_peek_last_error();
929 :
930 0 : if (ERR_GET_LIB(n) == ERR_LIB_PEM
931 0 : && ERR_GET_REASON(n) == PEM_R_NO_START_LINE)
932 : {
933 : /* end of file */
934 0 : ERR_clear_error();
935 0 : break;
936 : }
937 :
938 : /* some real error */
939 :
940 0 : *err = "PEM_read_bio_X509() failed";
941 0 : BIO_free(bio);
942 0 : ERR_clear_error();
943 0 : return NGX_ERROR;
944 : }
945 :
946 0 : len = i2d_X509(x509, &der);
947 0 : if (len < 0) {
948 0 : *err = "i2d_X509() failed";
949 0 : X509_free(x509);
950 0 : BIO_free(bio);
951 0 : ERR_clear_error();
952 0 : return NGX_ERROR;
953 : }
954 :
955 0 : total += len;
956 :
957 0 : X509_free(x509);
958 : }
959 :
960 0 : BIO_free(bio);
961 :
962 0 : return total;
963 : }
964 :
965 :
966 : int
967 0 : ngx_http_lua_ffi_priv_key_pem_to_der(const u_char *pem, size_t pem_len,
968 : u_char *der, char **err)
969 : {
970 : int len;
971 : BIO *in;
972 : EVP_PKEY *pkey;
973 :
974 0 : in = BIO_new_mem_buf((char *) pem, (int) pem_len);
975 0 : if (in == NULL) {
976 0 : *err = "BIO_new_mem_buf() failed";
977 0 : ERR_clear_error();
978 0 : return NGX_ERROR;
979 : }
980 :
981 0 : pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
982 0 : if (pkey == NULL) {
983 0 : BIO_free(in);
984 0 : *err = "PEM_read_bio_PrivateKey() failed";
985 0 : ERR_clear_error();
986 0 : return NGX_ERROR;
987 : }
988 :
989 0 : BIO_free(in);
990 :
991 0 : len = i2d_PrivateKey(pkey, &der);
992 0 : if (len < 0) {
993 0 : EVP_PKEY_free(pkey);
994 0 : *err = "i2d_PrivateKey() failed";
995 0 : ERR_clear_error();
996 0 : return NGX_ERROR;
997 : }
998 :
999 0 : EVP_PKEY_free(pkey);
1000 :
1001 0 : return len;
1002 : }
1003 :
1004 :
1005 : void *
1006 0 : ngx_http_lua_ffi_parse_pem_cert(const u_char *pem, size_t pem_len,
1007 : char **err)
1008 : {
1009 : BIO *bio;
1010 : X509 *x509;
1011 : u_long n;
1012 : STACK_OF(X509) *chain;
1013 :
1014 0 : bio = BIO_new_mem_buf((char *) pem, (int) pem_len);
1015 0 : if (bio == NULL) {
1016 0 : *err = "BIO_new_mem_buf() failed";
1017 0 : ERR_clear_error();
1018 0 : return NULL;
1019 : }
1020 :
1021 0 : x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
1022 0 : if (x509 == NULL) {
1023 0 : *err = "PEM_read_bio_X509_AUX() failed";
1024 0 : BIO_free(bio);
1025 0 : ERR_clear_error();
1026 0 : return NULL;
1027 : }
1028 :
1029 0 : chain = sk_X509_new_null();
1030 0 : if (chain == NULL) {
1031 0 : *err = "sk_X509_new_null() failed";
1032 0 : X509_free(x509);
1033 0 : BIO_free(bio);
1034 0 : ERR_clear_error();
1035 0 : return NULL;
1036 : }
1037 :
1038 0 : if (sk_X509_push(chain, x509) == 0) {
1039 0 : *err = "sk_X509_push() failed";
1040 0 : sk_X509_free(chain);
1041 0 : X509_free(x509);
1042 0 : BIO_free(bio);
1043 0 : ERR_clear_error();
1044 0 : return NULL;
1045 : }
1046 :
1047 : /* read rest of the chain */
1048 :
1049 : for ( ;; ) {
1050 :
1051 0 : x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
1052 0 : if (x509 == NULL) {
1053 0 : n = ERR_peek_last_error();
1054 :
1055 0 : if (ERR_GET_LIB(n) == ERR_LIB_PEM
1056 0 : && ERR_GET_REASON(n) == PEM_R_NO_START_LINE)
1057 : {
1058 : /* end of file */
1059 0 : ERR_clear_error();
1060 0 : break;
1061 : }
1062 :
1063 : /* some real error */
1064 :
1065 0 : *err = "PEM_read_bio_X509() failed";
1066 0 : sk_X509_pop_free(chain, X509_free);
1067 0 : BIO_free(bio);
1068 0 : ERR_clear_error();
1069 0 : return NULL;
1070 : }
1071 :
1072 0 : if (sk_X509_push(chain, x509) == 0) {
1073 0 : *err = "sk_X509_push() failed";
1074 0 : sk_X509_pop_free(chain, X509_free);
1075 0 : X509_free(x509);
1076 0 : BIO_free(bio);
1077 0 : ERR_clear_error();
1078 0 : return NULL;
1079 : }
1080 : }
1081 :
1082 0 : BIO_free(bio);
1083 :
1084 0 : return chain;
1085 : }
1086 :
1087 :
1088 : void
1089 0 : ngx_http_lua_ffi_free_cert(void *cdata)
1090 : {
1091 0 : STACK_OF(X509) *chain = cdata;
1092 :
1093 0 : sk_X509_pop_free(chain, X509_free);
1094 0 : }
1095 :
1096 :
1097 : void *
1098 0 : ngx_http_lua_ffi_parse_pem_priv_key(const u_char *pem, size_t pem_len,
1099 : char **err)
1100 : {
1101 : BIO *in;
1102 : EVP_PKEY *pkey;
1103 :
1104 0 : in = BIO_new_mem_buf((char *) pem, (int) pem_len);
1105 0 : if (in == NULL) {
1106 0 : *err = "BIO_new_mem_buf() failed";
1107 0 : ERR_clear_error();
1108 0 : return NULL;
1109 : }
1110 :
1111 0 : pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
1112 0 : if (pkey == NULL) {
1113 0 : *err = "PEM_read_bio_PrivateKey() failed";
1114 0 : BIO_free(in);
1115 0 : ERR_clear_error();
1116 0 : return NULL;
1117 : }
1118 :
1119 0 : BIO_free(in);
1120 :
1121 0 : return pkey;
1122 : }
1123 :
1124 :
1125 : void
1126 0 : ngx_http_lua_ffi_free_priv_key(void *cdata)
1127 : {
1128 0 : EVP_PKEY *pkey = cdata;
1129 :
1130 0 : EVP_PKEY_free(pkey);
1131 0 : }
1132 :
1133 :
1134 : int
1135 0 : ngx_http_lua_ffi_set_cert(ngx_http_request_t *r,
1136 : void *cdata, char **err)
1137 : {
1138 : #ifdef LIBRESSL_VERSION_NUMBER
1139 :
1140 : *err = "LibreSSL not supported";
1141 : return NGX_ERROR;
1142 :
1143 : #else
1144 :
1145 : # if OPENSSL_VERSION_NUMBER < 0x1000205fL
1146 :
1147 : *err = "at least OpenSSL 1.0.2e required but found " OPENSSL_VERSION_TEXT;
1148 : return NGX_ERROR;
1149 :
1150 : # else
1151 :
1152 : #ifdef OPENSSL_IS_BORINGSSL
1153 : size_t i;
1154 : #else
1155 : int i;
1156 : #endif
1157 0 : X509 *x509 = NULL;
1158 : ngx_ssl_conn_t *ssl_conn;
1159 0 : STACK_OF(X509) *chain = cdata;
1160 :
1161 0 : if (r->connection == NULL || r->connection->ssl == NULL) {
1162 0 : *err = "bad request";
1163 0 : return NGX_ERROR;
1164 : }
1165 :
1166 0 : ssl_conn = r->connection->ssl->connection;
1167 0 : if (ssl_conn == NULL) {
1168 0 : *err = "bad ssl conn";
1169 0 : return NGX_ERROR;
1170 : }
1171 :
1172 0 : if (sk_X509_num(chain) < 1) {
1173 0 : *err = "invalid certificate chain";
1174 0 : goto failed;
1175 : }
1176 :
1177 0 : x509 = sk_X509_value(chain, 0);
1178 0 : if (x509 == NULL) {
1179 0 : *err = "sk_X509_value() failed";
1180 0 : goto failed;
1181 : }
1182 :
1183 0 : if (SSL_use_certificate(ssl_conn, x509) == 0) {
1184 0 : *err = "SSL_use_certificate() failed";
1185 0 : goto failed;
1186 : }
1187 :
1188 0 : x509 = NULL;
1189 :
1190 : /* read rest of the chain */
1191 :
1192 0 : for (i = 1; i < sk_X509_num(chain); i++) {
1193 :
1194 0 : x509 = sk_X509_value(chain, i);
1195 0 : if (x509 == NULL) {
1196 0 : *err = "sk_X509_value() failed";
1197 0 : goto failed;
1198 : }
1199 :
1200 0 : if (SSL_add1_chain_cert(ssl_conn, x509) == 0) {
1201 0 : *err = "SSL_add1_chain_cert() failed";
1202 0 : goto failed;
1203 : }
1204 : }
1205 :
1206 0 : *err = NULL;
1207 0 : return NGX_OK;
1208 :
1209 0 : failed:
1210 :
1211 0 : ERR_clear_error();
1212 :
1213 0 : return NGX_ERROR;
1214 :
1215 : # endif /* OPENSSL_VERSION_NUMBER < 0x1000205fL */
1216 : #endif
1217 : }
1218 :
1219 :
1220 : int
1221 0 : ngx_http_lua_ffi_set_priv_key(ngx_http_request_t *r,
1222 : void *cdata, char **err)
1223 : {
1224 0 : EVP_PKEY *pkey = NULL;
1225 : ngx_ssl_conn_t *ssl_conn;
1226 :
1227 0 : if (r->connection == NULL || r->connection->ssl == NULL) {
1228 0 : *err = "bad request";
1229 0 : return NGX_ERROR;
1230 : }
1231 :
1232 0 : ssl_conn = r->connection->ssl->connection;
1233 0 : if (ssl_conn == NULL) {
1234 0 : *err = "bad ssl conn";
1235 0 : return NGX_ERROR;
1236 : }
1237 :
1238 0 : pkey = cdata;
1239 0 : if (pkey == NULL) {
1240 0 : *err = "invalid private key failed";
1241 0 : goto failed;
1242 : }
1243 :
1244 0 : if (SSL_use_PrivateKey(ssl_conn, pkey) == 0) {
1245 0 : *err = "SSL_use_PrivateKey() failed";
1246 0 : goto failed;
1247 : }
1248 :
1249 0 : return NGX_OK;
1250 :
1251 0 : failed:
1252 :
1253 0 : ERR_clear_error();
1254 :
1255 0 : return NGX_ERROR;
1256 : }
1257 :
1258 :
1259 : #endif /* NGX_LUA_NO_FFI_API */
1260 :
1261 :
1262 : #endif /* NGX_HTTP_SSL */
|