Controller: certificates storage interface.

This commit is contained in:
Valentin Bartenev 2018-09-20 15:27:08 +03:00
parent 2dfd8ffc2f
commit 8d844bc2aa
16 changed files with 2111 additions and 52 deletions

View file

@ -106,7 +106,7 @@ NXT_LIB_UNIT_SRCS="src/nxt_unit.c"
NXT_LIB_TLS_DEPS="src/nxt_tls.h"
NXT_LIB_TLS_SRCS=
NXT_LIB_TLS_SRCS="src/nxt_cert.c"
NXT_LIB_OPENSSL_SRCS="src/nxt_openssl.c"
NXT_LIB_GNUTLS_SRCS="src/nxt_gnutls.c"
NXT_LIB_CYASSL_SRCS="src/nxt_cyassl.c"

1204
src/nxt_cert.c Normal file

File diff suppressed because it is too large Load diff

32
src/nxt_cert.h Normal file
View file

@ -0,0 +1,32 @@
/*
* Copyright (C) Valentin V. Bartenev
* Copyright (C) NGINX, Inc.
*/
#ifndef _NXT_CERT_INCLUDED_
#define _NXT_CERT_INCLUDED_
typedef struct nxt_cert_s nxt_cert_t;
nxt_cert_t *nxt_cert_mem(nxt_task_t *task, nxt_buf_mem_t *mbuf);
void nxt_cert_destroy(nxt_cert_t *cert);
void nxt_cert_info_init(nxt_task_t *task, nxt_array_t *certs);
nxt_int_t nxt_cert_info_save(nxt_str_t *name, nxt_cert_t *cert);
nxt_conf_value_t *nxt_cert_info_get(nxt_str_t *name);
nxt_conf_value_t *nxt_cert_info_get_all(nxt_mp_t *mp);
nxt_int_t nxt_cert_info_delete(nxt_str_t *name);
nxt_array_t *nxt_cert_store_load(nxt_task_t *task);
void nxt_cert_store_release(nxt_array_t *certs);
void nxt_cert_store_get(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp,
nxt_port_rpc_handler_t handler, void *ctx);
void nxt_cert_store_delete(nxt_task_t *task, nxt_str_t *name, nxt_mp_t *mp);
void nxt_cert_store_get_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
void nxt_cert_store_delete_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
#endif /* _NXT_CERT_INCLUDED_ */

View file

@ -180,6 +180,33 @@ nxt_conf_set_string(nxt_conf_value_t *value, nxt_str_t *str)
}
nxt_int_t
nxt_conf_set_string_dup(nxt_conf_value_t *value, nxt_mp_t *mp, nxt_str_t *str)
{
nxt_str_t tmp, *ptr;
if (str->length > NXT_CONF_MAX_SHORT_STRING) {
value->type = NXT_CONF_VALUE_STRING;
ptr = nxt_str_dup(mp, &tmp, str);
if (nxt_slow_path(ptr == NULL)) {
return NXT_ERROR;
}
value->u.string.length = tmp.length;
value->u.string.start = tmp.start;
} else {
value->type = NXT_CONF_VALUE_SHORT_STRING;
value->u.str.length = str->length;
nxt_memcpy(value->u.str.start, str->start, str->length);
}
return NXT_OK;
}
int64_t
nxt_conf_get_integer(nxt_conf_value_t *value)
{
@ -246,6 +273,20 @@ nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name,
}
nxt_int_t
nxt_conf_set_member_string_dup(nxt_conf_value_t *object, nxt_mp_t *mp,
nxt_str_t *name, nxt_str_t *value, uint32_t index)
{
nxt_conf_object_member_t *member;
member = &object->u.object->members[index];
nxt_conf_set_string(&member->name, name);
return nxt_conf_set_string_dup(&member->value, mp, value);
}
void
nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name,
int64_t value, uint32_t index)
@ -261,6 +302,64 @@ nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name,
}
void
nxt_conf_set_member_null(nxt_conf_value_t *object, nxt_str_t *name,
uint32_t index)
{
nxt_conf_object_member_t *member;
member = &object->u.object->members[index];
nxt_conf_set_string(&member->name, name);
member->value.type = NXT_CONF_VALUE_NULL;
}
nxt_conf_value_t *
nxt_conf_create_array(nxt_mp_t *mp, nxt_uint_t count)
{
size_t size;
nxt_conf_value_t *value;
size = sizeof(nxt_conf_value_t)
+ sizeof(nxt_conf_array_t)
+ count * sizeof(nxt_conf_value_t);
value = nxt_mp_get(mp, size);
if (nxt_slow_path(value == NULL)) {
return NULL;
}
value->u.array = nxt_pointer_to(value, sizeof(nxt_conf_value_t));
value->u.array->count = count;
value->type = NXT_CONF_VALUE_ARRAY;
return value;
}
void
nxt_conf_set_element(nxt_conf_value_t *array, nxt_uint_t index,
nxt_conf_value_t *value)
{
array->u.array->elements[index] = *value;
}
nxt_int_t
nxt_conf_set_element_string_dup(nxt_conf_value_t *array, nxt_mp_t *mp,
nxt_uint_t index, nxt_str_t *value)
{
nxt_conf_value_t *element;
element = &array->u.array->elements[index];
return nxt_conf_set_string_dup(element, mp, value);
}
nxt_uint_t
nxt_conf_type(nxt_conf_value_t *value)
{

View file

@ -102,6 +102,8 @@ nxt_int_t nxt_conf_validate(nxt_conf_validation_t *vldt);
NXT_EXPORT void nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str);
NXT_EXPORT void nxt_conf_set_string(nxt_conf_value_t *value, nxt_str_t *str);
NXT_EXPORT nxt_int_t nxt_conf_set_string_dup(nxt_conf_value_t *value,
nxt_mp_t *mp, nxt_str_t *str);
NXT_EXPORT int64_t nxt_conf_get_integer(nxt_conf_value_t *value);
// FIXME reimplement and reorder functions below
@ -111,8 +113,18 @@ void nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name,
nxt_conf_value_t *value, uint32_t index);
void nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name,
nxt_str_t *value, uint32_t index);
nxt_int_t nxt_conf_set_member_string_dup(nxt_conf_value_t *object, nxt_mp_t *mp,
nxt_str_t *name, nxt_str_t *value, uint32_t index);
void nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name,
int64_t value, uint32_t index);
void nxt_conf_set_member_null(nxt_conf_value_t *object, nxt_str_t *name,
uint32_t index);
nxt_conf_value_t *nxt_conf_create_array(nxt_mp_t *mp, nxt_uint_t count);
void nxt_conf_set_element(nxt_conf_value_t *array, nxt_uint_t index,
nxt_conf_value_t *value);
nxt_int_t nxt_conf_set_element_string_dup(nxt_conf_value_t *array, nxt_mp_t *mp,
nxt_uint_t index, nxt_str_t *value);
#endif /* _NXT_CONF_INCLUDED_ */

View file

@ -6,6 +6,7 @@
#include <nxt_main.h>
#include <nxt_conf.h>
#include <nxt_cert.h>
#include <nxt_router.h>
@ -49,6 +50,10 @@ static nxt_int_t nxt_conf_vldt_error(nxt_conf_validation_t *vldt,
static nxt_int_t nxt_conf_vldt_listener(nxt_conf_validation_t *vldt,
nxt_str_t *name, nxt_conf_value_t *value);
#if (NXT_TLS)
static nxt_int_t nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
#endif
static nxt_int_t nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_app(nxt_conf_validation_t *vldt,
@ -138,12 +143,35 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_root_members[] = {
};
#if (NXT_TLS)
static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[] = {
{ nxt_string("certificate"),
NXT_CONF_VLDT_STRING,
&nxt_conf_vldt_certificate,
NULL },
NXT_CONF_VLDT_END
};
#endif
static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = {
{ nxt_string("application"),
NXT_CONF_VLDT_STRING,
&nxt_conf_vldt_app_name,
NULL },
#if (NXT_TLS)
{ nxt_string("tls"),
NXT_CONF_VLDT_OBJECT,
&nxt_conf_vldt_object,
(void *) &nxt_conf_vldt_tls_members },
#endif
NXT_CONF_VLDT_END
};
@ -467,6 +495,30 @@ nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, nxt_str_t *name,
}
#if (NXT_TLS)
static nxt_int_t
nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
nxt_str_t name;
nxt_conf_value_t *cert;
nxt_conf_get_string(value, &name);
cert = nxt_cert_info_get(&name);
if (cert == NULL) {
return nxt_conf_vldt_error(vldt, "Certificate \"%V\" is not found.",
&name);
}
return NXT_OK;
}
#endif
static nxt_int_t
nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)

View file

@ -9,6 +9,7 @@
#include <nxt_runtime.h>
#include <nxt_main_process.h>
#include <nxt_conf.h>
#include <nxt_cert.h>
typedef struct {
@ -72,6 +73,15 @@ static nxt_int_t nxt_controller_request_content_length(void *ctx,
static void nxt_controller_process_request(nxt_task_t *task,
nxt_controller_request_t *req);
static void nxt_controller_process_config(nxt_task_t *task,
nxt_controller_request_t *req, nxt_str_t *path);
#if (NXT_TLS)
static void nxt_controller_process_cert(nxt_task_t *task,
nxt_controller_request_t *req, nxt_str_t *path);
static void nxt_controller_process_cert_save(nxt_task_t *task,
nxt_port_recv_msg_t *msg, void *data);
static nxt_bool_t nxt_controller_cert_in_use(nxt_str_t *name);
#endif
static void nxt_controller_conf_handler(nxt_task_t *task,
nxt_port_recv_msg_t *msg, void *data);
static void nxt_controller_conf_store(nxt_task_t *task,
@ -124,6 +134,7 @@ nxt_controller_start(nxt_task_t *task, void *data)
nxt_conf_value_t *conf;
nxt_event_engine_t *engine;
nxt_conf_validation_t vldt;
nxt_controller_init_t *init;
rt = task->thread->runtime;
@ -144,9 +155,20 @@ nxt_controller_start(nxt_task_t *task, void *data)
nxt_queue_init(&nxt_controller_waiting_requests);
json = data;
init = data;
if (json->length == 0) {
#if (NXT_TLS)
if (init->certs != NULL) {
nxt_cert_info_init(task, init->certs);
nxt_cert_store_release(init->certs);
}
#endif
json = &init->conf;
if (json->start == NULL) {
return NXT_OK;
}
@ -789,10 +811,131 @@ nxt_controller_request_content_length(void *ctx, nxt_http_field_t *field,
static void
nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
{
uint32_t i, count;
nxt_str_t path;
nxt_conn_t *c;
nxt_conf_value_t *value;
nxt_controller_response_t resp;
#if (NXT_TLS)
nxt_conf_value_t *certs;
static nxt_str_t certificates = nxt_string("certificates");
#endif
static nxt_str_t config = nxt_string("config");
c = req->conn;
path = req->parser.path;
if (path.length > 1 && path.start[path.length - 1] == '/') {
path.length--;
}
if (nxt_str_start(&path, "/config", 7)
&& (path.length == 7 || path.start[7] == '/'))
{
if (path.length == 7) {
path.length = 1;
} else {
path.length -= 7;
path.start += 7;
}
nxt_controller_process_config(task, req, &path);
return;
}
#if (NXT_TLS)
if (nxt_str_start(&path, "/certificates", 13)
&& (path.length == 13 || path.start[13] == '/'))
{
if (path.length == 13) {
path.length = 1;
} else {
path.length -= 13;
path.start += 13;
}
nxt_controller_process_cert(task, req, &path);
return;
}
#endif
nxt_memzero(&resp, sizeof(nxt_controller_response_t));
if (path.length == 1 && path.start[0] == '/') {
if (!nxt_str_eq(&req->parser.method, "GET", 3)) {
goto invalid_method;
}
count = 1;
#if (NXT_TLS)
count++;
#endif
value = nxt_conf_create_object(c->mem_pool, count);
if (nxt_slow_path(value == NULL)) {
goto alloc_fail;
}
i = 0;
#if (NXT_TLS)
certs = nxt_cert_info_get_all(c->mem_pool);
if (nxt_slow_path(certs == NULL)) {
goto alloc_fail;
}
nxt_conf_set_member(value, &certificates, certs, i++);
#endif
nxt_conf_set_member(value, &config, nxt_controller_conf.root, i);
resp.status = 200;
resp.conf = value;
nxt_controller_response(task, req, &resp);
return;
}
resp.status = 404;
resp.title = (u_char *) "Value doesn't exist.";
resp.offset = -1;
nxt_controller_response(task, req, &resp);
return;
invalid_method:
resp.status = 405;
resp.title = (u_char *) "Invalid method.";
resp.offset = -1;
nxt_controller_response(task, req, &resp);
return;
alloc_fail:
resp.status = 500;
resp.title = (u_char *) "Memory allocation failed.";
resp.offset = -1;
nxt_controller_response(task, req, &resp);
return;
}
static void
nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req,
nxt_str_t *path)
{
nxt_mp_t *mp;
nxt_int_t rc;
nxt_str_t path;
nxt_conn_t *c;
nxt_buf_mem_t *mbuf;
nxt_conf_op_t *ops;
@ -803,29 +946,13 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
static const nxt_str_t empty_obj = nxt_string("{}");
c = req->conn;
path = req->parser.path;
if (nxt_str_start(&path, "/config", 7)) {
if (path.length == 7) {
path.length = 1;
} else if (path.start[7] == '/') {
path.length -= 7;
path.start += 7;
}
}
if (path.length > 1 && path.start[path.length - 1] == '/') {
path.length--;
}
nxt_memzero(&resp, sizeof(nxt_controller_response_t));
c = req->conn;
if (nxt_str_eq(&req->parser.method, "GET", 3)) {
value = nxt_conf_get_path(nxt_controller_conf.root, &path);
value = nxt_conf_get_path(nxt_controller_conf.root, path);
if (value == NULL) {
goto not_found;
@ -877,10 +1004,10 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
return;
}
if (path.length != 1) {
if (path->length != 1) {
rc = nxt_conf_op_compile(c->mem_pool, &ops,
nxt_controller_conf.root,
&path, value);
path, value);
if (rc != NXT_OK) {
nxt_mp_destroy(mp);
@ -948,7 +1075,7 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
return;
}
if (path.length == 1) {
if (path->length == 1) {
mp = nxt_mp_create(1024, 128, 256, 32);
if (nxt_slow_path(mp == NULL)) {
@ -960,7 +1087,7 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
} else {
rc = nxt_conf_op_compile(c->mem_pool, &ops,
nxt_controller_conf.root,
&path, NULL);
path, NULL);
if (rc != NXT_OK) {
if (rc == NXT_DECLINED) {
@ -1070,6 +1197,265 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
}
#if (NXT_TLS)
static void
nxt_controller_process_cert(nxt_task_t *task,
nxt_controller_request_t *req, nxt_str_t *path)
{
u_char *p;
nxt_str_t name;
nxt_int_t ret;
nxt_conn_t *c;
nxt_cert_t *cert;
nxt_conf_value_t *value;
nxt_controller_response_t resp;
name.length = path->length - 1;
name.start = path->start + 1;
p = nxt_memchr(name.start, '/', name.length);
if (p != NULL) {
name.length = p - name.start;
path->length -= p - path->start;
path->start = p;
} else {
path = NULL;
}
nxt_memzero(&resp, sizeof(nxt_controller_response_t));
c = req->conn;
if (nxt_str_eq(&req->parser.method, "GET", 3)) {
if (name.length != 0) {
value = nxt_cert_info_get(&name);
if (value == NULL) {
goto cert_not_found;
}
if (path != NULL) {
value = nxt_conf_get_path(value, path);
if (value == NULL) {
goto not_found;
}
}
} else {
value = nxt_cert_info_get_all(c->mem_pool);
if (value == NULL) {
goto alloc_fail;
}
}
resp.status = 200;
resp.conf = value;
nxt_controller_response(task, req, &resp);
return;
}
if (name.length == 0 || path != NULL) {
goto invalid_name;
}
if (nxt_str_eq(&req->parser.method, "PUT", 3)) {
value = nxt_cert_info_get(&name);
if (value != NULL) {
goto exists_cert;
}
cert = nxt_cert_mem(task, &c->read->mem);
if (cert == NULL) {
goto invalid_cert;
}
ret = nxt_cert_info_save(&name, cert);
nxt_cert_destroy(cert);
if (nxt_slow_path(ret != NXT_OK)) {
goto alloc_fail;
}
nxt_cert_store_get(task, &name, c->mem_pool,
nxt_controller_process_cert_save, req);
return;
}
if (nxt_str_eq(&req->parser.method, "DELETE", 6)) {
if (nxt_controller_cert_in_use(&name)) {
goto cert_in_use;
}
if (nxt_cert_info_delete(&name) != NXT_OK) {
goto cert_not_found;
}
nxt_cert_store_delete(task, &name, c->mem_pool);
resp.status = 200;
resp.title = (u_char *) "Certificate deleted.";
nxt_controller_response(task, req, &resp);
return;
}
resp.status = 405;
resp.title = (u_char *) "Invalid method.";
resp.offset = -1;
nxt_controller_response(task, req, &resp);
return;
invalid_name:
resp.status = 400;
resp.title = (u_char *) "Invalid certificate name.";
resp.offset = -1;
nxt_controller_response(task, req, &resp);
return;
invalid_cert:
resp.status = 400;
resp.title = (u_char *) "Invalid certificate.";
resp.offset = -1;
nxt_controller_response(task, req, &resp);
return;
exists_cert:
resp.status = 400;
resp.title = (u_char *) "Certificate already exists.";
resp.offset = -1;
nxt_controller_response(task, req, &resp);
return;
cert_in_use:
resp.status = 400;
resp.title = (u_char *) "Certificate is used in the configuration.";
resp.offset = -1;
nxt_controller_response(task, req, &resp);
return;
cert_not_found:
resp.status = 404;
resp.title = (u_char *) "Certificate doesn't exist.";
resp.offset = -1;
nxt_controller_response(task, req, &resp);
return;
not_found:
resp.status = 404;
resp.title = (u_char *) "Invalid path.";
resp.offset = -1;
nxt_controller_response(task, req, &resp);
return;
alloc_fail:
resp.status = 500;
resp.title = (u_char *) "Memory allocation failed.";
resp.offset = -1;
nxt_controller_response(task, req, &resp);
return;
}
static void
nxt_controller_process_cert_save(nxt_task_t *task, nxt_port_recv_msg_t *msg,
void *data)
{
nxt_conn_t *c;
nxt_buf_mem_t *mbuf;
nxt_controller_request_t *req;
nxt_controller_response_t resp;
req = data;
nxt_memzero(&resp, sizeof(nxt_controller_response_t));
if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
resp.status = 500;
resp.title = (u_char *) "Failed to store certificate.";
nxt_controller_response(task, req, &resp);
return;
}
c = req->conn;
mbuf = &c->read->mem;
nxt_fd_write(msg->fd, mbuf->pos, nxt_buf_mem_used_size(mbuf));
nxt_fd_close(msg->fd);
nxt_memzero(&resp, sizeof(nxt_controller_response_t));
resp.status = 200;
resp.title = (u_char *) "Certificate chain uploaded.";
nxt_controller_response(task, req, &resp);
}
static nxt_bool_t
nxt_controller_cert_in_use(nxt_str_t *name)
{
uint32_t next;
nxt_str_t str;
nxt_conf_value_t *listeners, *listener, *value;
static nxt_str_t listeners_path = nxt_string("/listeners");
static nxt_str_t certificate_path = nxt_string("/tls/certificate");
listeners = nxt_conf_get_path(nxt_controller_conf.root, &listeners_path);
if (listeners != NULL) {
next = 0;
for ( ;; ) {
listener = nxt_conf_next_object_member(listeners, &str, &next);
if (listener == NULL) {
break;
}
value = nxt_conf_get_path(listener, &certificate_path);
if (value == NULL) {
continue;
}
nxt_conf_get_string(value, &str);
if (nxt_strstr_eq(&str, name)) {
return 1;
}
}
}
return 0;
}
#endif
static void
nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
void *data)

View file

@ -10,6 +10,9 @@
#include <nxt_main_process.h>
#include <nxt_conf.h>
#include <nxt_router.h>
#if (NXT_TLS)
#include <nxt_cert.h>
#endif
typedef struct {
@ -336,6 +339,10 @@ static nxt_port_handlers_t nxt_main_process_port_handlers = {
.socket = nxt_main_port_socket_handler,
.modules = nxt_main_port_modules_handler,
.conf_store = nxt_main_port_conf_store_handler,
#if (NXT_TLS)
.cert_get = nxt_cert_store_get_handler,
.cert_delete = nxt_cert_store_delete_handler,
#endif
.access_log = nxt_main_port_access_log_handler,
.rpc_ready = nxt_port_rpc_handler,
.rpc_error = nxt_port_rpc_handler,
@ -439,13 +446,16 @@ static nxt_int_t
nxt_main_create_controller_process(nxt_task_t *task, nxt_runtime_t *rt,
nxt_process_init_t *init)
{
ssize_t n;
nxt_int_t ret;
nxt_str_t conf;
nxt_file_t file;
nxt_file_info_t fi;
ssize_t n;
nxt_int_t ret;
nxt_str_t *conf;
nxt_file_t file;
nxt_file_info_t fi;
nxt_controller_init_t ctrl_init;
conf.length = 0;
nxt_memzero(&ctrl_init, sizeof(nxt_controller_init_t));
conf = &ctrl_init.conf;
nxt_memzero(&file, sizeof(nxt_file_t));
@ -457,19 +467,19 @@ nxt_main_create_controller_process(nxt_task_t *task, nxt_runtime_t *rt,
ret = nxt_file_info(&file, &fi);
if (nxt_fast_path(ret == NXT_OK && nxt_is_file(&fi))) {
conf.length = nxt_file_size(&fi);
conf.start = nxt_malloc(conf.length);
conf->length = nxt_file_size(&fi);
conf->start = nxt_malloc(conf->length);
if (nxt_slow_path(conf.start == NULL)) {
if (nxt_slow_path(conf->start == NULL)) {
nxt_file_close(task, &file);
return NXT_ERROR;
}
n = nxt_file_read(&file, conf.start, conf.length, 0);
n = nxt_file_read(&file, conf->start, conf->length, 0);
if (nxt_slow_path(n != (ssize_t) conf.length)) {
conf.length = 0;
nxt_free(conf.start);
if (nxt_slow_path(n != (ssize_t) conf->length)) {
nxt_free(conf->start);
conf->start = NULL;
nxt_alert(task, "failed to restore previous configuration: "
"cannot read the file");
@ -479,12 +489,24 @@ nxt_main_create_controller_process(nxt_task_t *task, nxt_runtime_t *rt,
nxt_file_close(task, &file);
}
init->data = &conf;
#if (NXT_TLS)
ctrl_init.certs = nxt_cert_store_load(task);
#endif
init->data = &ctrl_init;
ret = nxt_main_create_worker_process(task, rt, init);
if (ret == NXT_OK && conf.length != 0) {
nxt_free(conf.start);
if (ret == NXT_OK) {
if (conf->start != NULL) {
nxt_free(conf->start);
}
#if (NXT_TLS)
if (ctrl_init.certs != NULL) {
nxt_cert_store_release(ctrl_init.certs);
}
#endif
}
return ret;

View file

@ -19,6 +19,14 @@ typedef enum {
} nxt_socket_error_t;
typedef struct {
nxt_str_t conf;
#if (NXT_TLS)
nxt_array_t *certs;
#endif
} nxt_controller_init_t;
nxt_int_t nxt_main_process_start(nxt_thread_t *thr, nxt_task_t *task,
nxt_runtime_t *runtime);
void nxt_main_stop_all_processes(nxt_task_t *task, nxt_runtime_t *runtime);

View file

@ -40,6 +40,7 @@ static void nxt_openssl_locks_free(void);
#endif
static nxt_int_t nxt_openssl_server_init(nxt_task_t *task,
nxt_tls_conf_t *conf);
static nxt_uint_t nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd);
static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf);
static void nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf,
nxt_conn_t *c);
@ -246,7 +247,8 @@ static nxt_int_t
nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf)
{
SSL_CTX *ctx;
const char *certificate, *key, *ciphers, *ca_certificate;
nxt_fd_t fd;
const char *ciphers, *ca_certificate;
STACK_OF(X509_NAME) *list;
ctx = SSL_CTX_new(SSLv23_server_method());
@ -284,15 +286,14 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf)
#endif
certificate = conf->certificate;
fd = conf->chain_file;
if (SSL_CTX_use_certificate_chain_file(ctx, certificate) == 0) {
if (nxt_openssl_chain_file(ctx, fd) != NXT_OK) {
nxt_openssl_log_error(task, NXT_LOG_ALERT,
"SSL_CTX_use_certificate_file(\"%s\") failed",
certificate);
"nxt_openssl_chain_file() failed");
goto fail;
}
/*
key = conf->certificate_key;
if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) == 0) {
@ -301,7 +302,7 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf)
key);
goto fail;
}
*/
ciphers = (conf->ciphers != NULL) ? conf->ciphers : "HIGH:!aNULL:!MD5";
if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) {
@ -358,6 +359,85 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf)
}
static nxt_uint_t
nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd)
{
BIO *bio;
X509 *cert, *ca;
long reason;
EVP_PKEY *key;
nxt_uint_t ret;
bio = BIO_new(BIO_s_fd());
if (bio == NULL) {
return NXT_ERROR;
}
BIO_set_fd(bio, fd, BIO_CLOSE);
ret = NXT_ERROR;
cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
if (cert == NULL) {
goto end;
}
if (SSL_CTX_use_certificate(ctx, cert) != 1) {
goto end;
}
for ( ;; ) {
ca = PEM_read_bio_X509(bio, NULL, NULL, NULL);
if (ca == NULL) {
reason = ERR_GET_REASON(ERR_peek_last_error());
if (reason != PEM_R_NO_START_LINE) {
goto end;
}
ERR_clear_error();
break;
}
/*
* Note that ca isn't freed if it was successfully added to the chain,
* while the main certificate needs a X509_free() call, since
* its reference count is increased by SSL_CTX_use_certificate().
*/
#if OPENSSL_VERSION_NUMBER > 0x10002000L
if (SSL_CTX_add0_chain_cert(ctx, ca) != 1) {
#else
if (SSL_CTX_add_extra_chain_cert(ctx, ca) != 1) {
#endif
X509_free(ca);
goto end;
}
}
if (BIO_reset(bio) != 0) {
goto end;
}
key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
if (key == NULL) {
goto end;
}
if (SSL_CTX_use_PrivateKey(ctx, key) == 1) {
ret = NXT_OK;
}
EVP_PKEY_free(key);
end:
X509_free(cert);
BIO_free(bio);
return ret;
}
static void
nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf)
{

View file

@ -18,6 +18,8 @@ struct nxt_port_handlers_s {
nxt_port_handler_t socket;
nxt_port_handler_t modules;
nxt_port_handler_t conf_store;
nxt_port_handler_t cert_get;
nxt_port_handler_t cert_delete;
nxt_port_handler_t access_log;
/* File descriptor exchange. */
@ -57,6 +59,8 @@ typedef enum {
_NXT_PORT_MSG_SOCKET = nxt_port_handler_idx(socket),
_NXT_PORT_MSG_MODULES = nxt_port_handler_idx(modules),
_NXT_PORT_MSG_CONF_STORE = nxt_port_handler_idx(conf_store),
_NXT_PORT_MSG_CERT_GET = nxt_port_handler_idx(cert_get),
_NXT_PORT_MSG_CERT_DELETE = nxt_port_handler_idx(cert_delete),
_NXT_PORT_MSG_ACCESS_LOG = nxt_port_handler_idx(access_log),
_NXT_PORT_MSG_CHANGE_FILE = nxt_port_handler_idx(change_file),
@ -81,6 +85,8 @@ typedef enum {
NXT_PORT_MSG_SOCKET = _NXT_PORT_MSG_SOCKET | NXT_PORT_MSG_LAST,
NXT_PORT_MSG_MODULES = _NXT_PORT_MSG_MODULES | NXT_PORT_MSG_LAST,
NXT_PORT_MSG_CONF_STORE = _NXT_PORT_MSG_CONF_STORE | NXT_PORT_MSG_LAST,
NXT_PORT_MSG_CERT_GET = _NXT_PORT_MSG_CERT_GET | NXT_PORT_MSG_LAST,
NXT_PORT_MSG_CERT_DELETE = _NXT_PORT_MSG_CERT_DELETE | NXT_PORT_MSG_LAST,
NXT_PORT_MSG_ACCESS_LOG = _NXT_PORT_MSG_ACCESS_LOG | NXT_PORT_MSG_LAST,
NXT_PORT_MSG_CHANGE_FILE = _NXT_PORT_MSG_CHANGE_FILE | NXT_PORT_MSG_LAST,

View file

@ -7,6 +7,9 @@
#include <nxt_router.h>
#include <nxt_conf.h>
#if (NXT_TLS)
#include <nxt_cert.h>
#endif
#include <nxt_http.h>
#include <nxt_port_memory_int.h>
#include <nxt_unit_request.h>
@ -32,6 +35,18 @@ typedef struct {
} nxt_router_listener_conf_t;
#if (NXT_TLS)
typedef struct {
nxt_str_t name;
nxt_socket_conf_t *conf;
nxt_queue_link_t link; /* for nxt_socket_conf_t.tls */
} nxt_router_tlssock_t;
#endif
typedef struct nxt_msg_info_s {
nxt_buf_t *buf;
nxt_port_mmap_tracking_t tracking;
@ -156,6 +171,12 @@ static void nxt_router_listen_socket_ready(nxt_task_t *task,
nxt_port_recv_msg_t *msg, void *data);
static void nxt_router_listen_socket_error(nxt_task_t *task,
nxt_port_recv_msg_t *msg, void *data);
#if (NXT_TLS)
static void nxt_router_tls_rpc_create(nxt_task_t *task,
nxt_router_temp_conf_t *tmcf, nxt_router_tlssock_t *tls);
static void nxt_router_tls_rpc_handler(nxt_task_t *task,
nxt_port_recv_msg_t *msg, void *data);
#endif
static void nxt_router_app_rpc_create(nxt_task_t *task,
nxt_router_temp_conf_t *tmcf, nxt_app_t *app);
static void nxt_router_app_prefork_ready(nxt_task_t *task,
@ -957,6 +978,10 @@ nxt_router_temp_conf(nxt_task_t *task)
nxt_queue_init(&tmcf->pending);
nxt_queue_init(&tmcf->creating);
#if (NXT_TLS)
nxt_queue_init(&tmcf->tls);
#endif
nxt_queue_init(&tmcf->apps);
nxt_queue_init(&tmcf->previous);
@ -1002,6 +1027,9 @@ nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
nxt_router_conf_t *rtcf;
nxt_router_temp_conf_t *tmcf;
const nxt_event_interface_t *interface;
#if (NXT_TLS)
nxt_router_tlssock_t *tls;
#endif
tmcf = obj;
@ -1018,6 +1046,19 @@ nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
return;
}
#if (NXT_TLS)
qlk = nxt_queue_first(&tmcf->tls);
if (qlk != nxt_queue_tail(&tmcf->tls)) {
nxt_queue_remove(qlk);
tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link);
nxt_router_tls_rpc_create(task, tmcf, tls);
return;
}
#endif
nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) {
if (nxt_router_app_need_start(app)) {
@ -1332,11 +1373,17 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
nxt_router_app_conf_t apcf;
nxt_router_access_log_t *access_log;
nxt_router_listener_conf_t lscf;
#if (NXT_TLS)
nxt_router_tlssock_t *tls;
#endif
static nxt_str_t http_path = nxt_string("/settings/http");
static nxt_str_t applications_path = nxt_string("/applications");
static nxt_str_t listeners_path = nxt_string("/listeners");
static nxt_str_t access_log_path = nxt_string("/access_log");
#if (NXT_TLS)
static nxt_str_t certificate_path = nxt_string("/tls/certificate");
#endif
conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
if (conf == NULL) {
@ -1588,6 +1635,26 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
}
}
#if (NXT_TLS)
value = nxt_conf_get_path(listener, &certificate_path);
if (value != NULL) {
nxt_conf_get_string(value, &name);
tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t));
if (nxt_slow_path(tls == NULL)) {
goto fail;
}
tls->name = name;
tls->conf = skcf;
nxt_queue_insert_tail(&tmcf->tls, &tls->link);
}
#endif
skcf->listen->handler = nxt_http_conn_init;
skcf->router_conf = tmcf->router_conf;
skcf->router_conf->count++;
@ -1956,6 +2023,75 @@ nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
}
#if (NXT_TLS)
static void
nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
nxt_router_tlssock_t *tls)
{
nxt_socket_rpc_t *rpc;
rpc = nxt_mp_alloc(tmcf->mem_pool, sizeof(nxt_socket_rpc_t));
if (rpc == NULL) {
nxt_router_conf_error(task, tmcf);
return;
}
rpc->socket_conf = tls->conf;
rpc->temp_conf = tmcf;
nxt_cert_store_get(task, &tls->name, tmcf->mem_pool,
nxt_router_tls_rpc_handler, rpc);
}
static void
nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
void *data)
{
nxt_mp_t *mp;
nxt_int_t ret;
nxt_tls_conf_t *tlscf;
nxt_socket_rpc_t *rpc;
nxt_router_temp_conf_t *tmcf;
nxt_debug(task, "tls rpc handler");
rpc = data;
tmcf = rpc->temp_conf;
if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
goto fail;
}
mp = tmcf->router_conf->mem_pool;
tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t));
if (nxt_slow_path(tlscf == NULL)) {
goto fail;
}
tlscf->chain_file = msg->fd;
ret = task->thread->runtime->tls->server_init(task, tlscf);
if (nxt_slow_path(ret != NXT_OK)) {
goto fail;
}
rpc->socket_conf->tls = tlscf;
nxt_work_queue_add(&task->thread->engine->fast_work_queue,
nxt_router_conf_apply, task, tmcf, NULL);
return;
fail:
nxt_router_conf_error(task, tmcf);
}
#endif
static void
nxt_router_app_rpc_create(nxt_task_t *task,
nxt_router_temp_conf_t *tmcf, nxt_app_t *app)

View file

@ -59,6 +59,10 @@ typedef struct {
nxt_queue_t keeping; /* of nxt_socket_conf_t */
nxt_queue_t deleting; /* of nxt_socket_conf_t */
#if (NXT_TLS)
nxt_queue_t tls; /* of nxt_router_tlssock_t */
#endif
nxt_queue_t apps; /* of nxt_app_t */
nxt_queue_t previous; /* of nxt_app_t */

View file

@ -762,6 +762,23 @@ nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt)
rt->conf_tmp = (char *) file_name.start;
ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%scerts/%Z",
rt->state, slash);
if (nxt_slow_path(ret != NXT_OK)) {
return NXT_ERROR;
}
ret = mkdir((char *) file_name.start, S_IRWXU);
if (nxt_fast_path(ret == 0 || nxt_errno == EEXIST)) {
rt->certs.length = file_name.len;
rt->certs.start = file_name.start;
} else {
nxt_alert(task, "Unable to create certificates storage directory: "
"mkdir(%s) failed %E", file_name.start, nxt_errno);
}
control.length = nxt_strlen(rt->control);
control.start = (u_char *) rt->control;

View file

@ -68,6 +68,8 @@ struct nxt_runtime_s {
const char *conf_tmp;
const char *control;
nxt_str_t certs;
nxt_queue_t engines; /* of nxt_event_engine_t */
nxt_sockaddr_t *controller_listen;

View file

@ -44,8 +44,7 @@ struct nxt_tls_conf_s {
const nxt_tls_lib_t *lib;
char *certificate;
char *certificate_key;
nxt_fd_t chain_file;
char *ciphers;
char *ca_certificate;