Skip to content

Commit

Permalink
Create the SSL_CTX for QUIC before chroot and privilege drop (#1187)
Browse files Browse the repository at this point in the history
Fixes #1185 by creating the SSL_CTX for QUIC before chroot and
privilege drop, just like the other SSL_CTX creations.

---------

Co-authored-by: Wouter Wijngaards <[email protected]>
  • Loading branch information
gthess and wcawijngaards authored Dec 3, 2024
1 parent b4a9c8b commit 61d7250
Show file tree
Hide file tree
Showing 12 changed files with 90 additions and 126 deletions.
3 changes: 3 additions & 0 deletions daemon/daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,9 @@ daemon_delete(struct daemon* daemon)
listen_sslctx_delete_ticket_keys();
SSL_CTX_free((SSL_CTX*)daemon->listen_sslctx);
SSL_CTX_free((SSL_CTX*)daemon->connect_sslctx);
#endif
#ifdef HAVE_NGTCP2
SSL_CTX_free((SSL_CTX*)daemon->quic_sslctx);
#endif
free(daemon);
/* lex cleanup */
Expand Down
2 changes: 2 additions & 0 deletions daemon/daemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ struct daemon {
struct daemon_remote* rc;
/** ssl context for listening to dnstcp over ssl, and connecting ssl */
void* listen_sslctx, *connect_sslctx;
/** ssl context for listening to quic */
void* quic_sslctx;
/** num threads allocated */
int num;
/** num threads allocated in the previous config or 0 at first */
Expand Down
13 changes: 10 additions & 3 deletions daemon/unbound.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,8 +494,9 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
fatal_exit("could not set up remote-control");
if(cfg->ssl_service_key && cfg->ssl_service_key[0]) {
if(!(daemon->listen_sslctx = listen_sslctx_create(
cfg->ssl_service_key, cfg->ssl_service_pem, NULL)))
cfg->ssl_service_key, cfg->ssl_service_pem, NULL))) {
fatal_exit("could not set up listen SSL_CTX");
}
if(cfg->tls_ciphers && cfg->tls_ciphers[0]) {
if (!SSL_CTX_set_cipher_list(daemon->listen_sslctx, cfg->tls_ciphers)) {
fatal_exit("failed to set tls-cipher %s", cfg->tls_ciphers);
Expand All @@ -507,18 +508,24 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
fatal_exit("failed to set tls-ciphersuites %s", cfg->tls_ciphersuites);
}
}
#endif
#endif /* HAVE_SSL_CTX_SET_CIPHERSUITES */
if(cfg->tls_session_ticket_keys.first &&
cfg->tls_session_ticket_keys.first->str[0] != 0) {
if(!listen_sslctx_setup_ticket_keys(daemon->listen_sslctx, cfg->tls_session_ticket_keys.first)) {
fatal_exit("could not set session ticket SSL_CTX");
}
}
#ifdef HAVE_NGTCP2
if(!(daemon->quic_sslctx = quic_sslctx_create(
cfg->ssl_service_key, cfg->ssl_service_pem, NULL))) {
fatal_exit("could not set up quic SSL_CTX");
}
#endif /* HAVE_NGTCP2 */
}
if(!(daemon->connect_sslctx = connect_sslctx_create(NULL, NULL,
cfg->tls_cert_bundle, cfg->tls_win_cert)))
fatal_exit("could not set up connect SSL_CTX");
#endif
#endif /* HAVE_SSL */

/* init syslog (as root) if needed, before daemonize, otherwise
* a fork error could not be printed since daemonize closed stderr.*/
Expand Down
4 changes: 2 additions & 2 deletions daemon/worker.c
Original file line number Diff line number Diff line change
Expand Up @@ -2174,9 +2174,9 @@ worker_init(struct worker* worker, struct config_file *cfg,
cfg->harden_large_queries, cfg->http_max_streams,
cfg->http_endpoint, cfg->http_notls_downstream,
worker->daemon->tcl, worker->daemon->listen_sslctx,
worker->daemon->quic_sslctx,
dtenv, worker->daemon->doq_table, worker->env.rnd,
cfg->ssl_service_key, cfg->ssl_service_pem, cfg,
worker_handle_request, worker);
cfg, worker_handle_request, worker);
if(!worker->front) {
log_err("could not create listening sockets");
worker_delete(worker);
Expand Down
71 changes: 35 additions & 36 deletions services/listen_dnsport.c
Original file line number Diff line number Diff line change
Expand Up @@ -1523,9 +1523,9 @@ listen_create(struct comm_base* base, struct listen_port* ports,
size_t bufsize, int tcp_accept_count, int tcp_idle_timeout,
int harden_large_queries, uint32_t http_max_streams,
char* http_endpoint, int http_notls, struct tcl_list* tcp_conn_limit,
void* sslctx, struct dt_env* dtenv, struct doq_table* doq_table,
struct ub_randstate* rnd, const char* ssl_service_key,
const char* ssl_service_pem, struct config_file* cfg,
void* sslctx, void* quic_sslctx, struct dt_env* dtenv,
struct doq_table* doq_table,
struct ub_randstate* rnd,struct config_file* cfg,
comm_point_callback_type* cb, void *cb_arg)
{
struct listen_dnsport* front = (struct listen_dnsport*)
Expand Down Expand Up @@ -1558,8 +1558,7 @@ listen_create(struct comm_base* base, struct listen_port* ports,
#endif
cp = comm_point_create_doq(base, ports->fd,
front->udp_buff, cb, cb_arg, ports->socket,
doq_table, rnd, ssl_service_key,
ssl_service_pem, cfg);
doq_table, rnd, quic_sslctx, cfg);
} else if(ports->ftype == listen_type_tcp ||
ports->ftype == listen_type_tcp_dnscrypt) {
cp = comm_point_create_tcp(base, ports->fd,
Expand Down Expand Up @@ -1620,10 +1619,13 @@ listen_create(struct comm_base* base, struct listen_port* ports,
(ports->ftype == listen_type_udpancil) ||
(ports->ftype == listen_type_tcp_dnscrypt) ||
(ports->ftype == listen_type_udp_dnscrypt) ||
(ports->ftype == listen_type_udpancil_dnscrypt))
(ports->ftype == listen_type_udpancil_dnscrypt)) {
cp->ssl = NULL;
else
} else if(ports->ftype == listen_type_doq) {
cp->ssl = quic_sslctx;
} else {
cp->ssl = sslctx;
}
cp->dtenv = dtenv;
cp->do_not_close = 1;
#ifdef USE_DNSCRYPT
Expand Down Expand Up @@ -4598,10 +4600,9 @@ doq_alpn_select_cb(SSL* ATTR_UNUSED(ssl), const unsigned char** out,
return SSL_TLSEXT_ERR_ALERT_FATAL;
}

/** create new tls session for server doq connection */
static SSL_CTX*
doq_ctx_server_setup(struct doq_server_socket* doq_socket)
void* quic_sslctx_create(char* key, char* pem, char* verifypem)
{
#ifdef HAVE_NGTCP2
char* sid_ctx = "unbound server";
#ifndef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_SERVER_CONTEXT
SSL_QUIC_METHOD* quic_method;
Expand All @@ -4611,6 +4612,16 @@ doq_ctx_server_setup(struct doq_server_socket* doq_socket)
log_crypto_err("Could not SSL_CTX_new");
return NULL;
}
if(!key || key[0] == 0) {
log_err("doq: error, no tls-service-key file specified");
SSL_CTX_free(ctx);
return NULL;
}
if(!pem || pem[0] == 0) {
log_err("doq: error, no tls-service-pem file specified");
SSL_CTX_free(ctx);
return NULL;
}
SSL_CTX_set_options(ctx,
(SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
SSL_OP_SINGLE_ECDH_USE |
Expand All @@ -4623,43 +4634,37 @@ doq_ctx_server_setup(struct doq_server_socket* doq_socket)
SSL_CTX_set_alpn_select_cb(ctx, doq_alpn_select_cb, NULL);
#endif
SSL_CTX_set_default_verify_paths(ctx);
if(!SSL_CTX_use_certificate_chain_file(ctx,
doq_socket->ssl_service_pem)) {
log_err("doq: error for cert file: %s",
doq_socket->ssl_service_pem);
if(!SSL_CTX_use_certificate_chain_file(ctx, pem)) {
log_err("doq: error for cert file: %s", pem);
log_crypto_err("doq: error in "
"SSL_CTX_use_certificate_chain_file");
SSL_CTX_free(ctx);
return NULL;
}
if(!SSL_CTX_use_PrivateKey_file(ctx, doq_socket->ssl_service_key,
SSL_FILETYPE_PEM)) {
log_err("doq: error for private key file: %s",
doq_socket->ssl_service_key);
if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
log_err("doq: error for private key file: %s", key);
log_crypto_err("doq: error in SSL_CTX_use_PrivateKey_file");
SSL_CTX_free(ctx);
return NULL;
}
if(!SSL_CTX_check_private_key(ctx)) {
log_err("doq: error for key file: %s",
doq_socket->ssl_service_key);
log_err("doq: error for key file: %s", key);
log_crypto_err("doq: error in SSL_CTX_check_private_key");
SSL_CTX_free(ctx);
return NULL;
}
SSL_CTX_set_session_id_context(ctx, (void*)sid_ctx, strlen(sid_ctx));
if(doq_socket->ssl_verify_pem && doq_socket->ssl_verify_pem[0]) {
if(!SSL_CTX_load_verify_locations(ctx,
doq_socket->ssl_verify_pem, NULL)) {
if(verifypem && verifypem[0]) {
if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) {
log_err("doq: error for verify pem file: %s",
doq_socket->ssl_verify_pem);
verifypem);
log_crypto_err("doq: error in "
"SSL_CTX_load_verify_locations");
SSL_CTX_free(ctx);
return NULL;
}
SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(
doq_socket->ssl_verify_pem));
verifypem));
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|
SSL_VERIFY_CLIENT_ONCE|
SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
Expand All @@ -4672,7 +4677,7 @@ doq_ctx_server_setup(struct doq_server_socket* doq_socket)
SSL_CTX_free(ctx);
return NULL;
}
#else
#else /* HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_SERVER_CONTEXT */
/* The quic_method needs to remain valid during the SSL_CTX
* lifetime, so we allocate it. It is freed with the
* doq_server_socket. */
Expand All @@ -4690,6 +4695,10 @@ doq_ctx_server_setup(struct doq_server_socket* doq_socket)
SSL_CTX_set_quic_method(ctx, doq_socket->quic_method);
#endif
return ctx;
#else /* HAVE_NGTCP2 */
(void)key; (void)pem; (void)verifypem;
return NULL;
#endif /* HAVE_NGTCP2 */
}

/** Get the ngtcp2_conn from ssl userdata of type ngtcp2_conn_ref */
Expand Down Expand Up @@ -4720,16 +4729,6 @@ doq_ssl_server_setup(SSL_CTX* ctx, struct doq_conn* conn)
return ssl;
}

/** setup the doq_socket server tls context */
int
doq_socket_setup_ctx(struct doq_server_socket* doq_socket)
{
doq_socket->ctx = doq_ctx_server_setup(doq_socket);
if(!doq_socket->ctx)
return 0;
return 1;
}

int
doq_conn_setup(struct doq_conn* conn, uint8_t* scid, size_t scidlen,
uint8_t* ocid, size_t ocidlen, const uint8_t* token, size_t tokenlen)
Expand Down
21 changes: 13 additions & 8 deletions services/listen_dnsport.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,10 @@ int resolve_interface_names(char** ifs, int num_ifs,
* @param http_notls: no TLS for http downstream
* @param tcp_conn_limit: TCP connection limit info.
* @param sslctx: nonNULL if ssl context.
* @param quic_sslctx: nonNULL if quic ssl context.
* @param dtenv: nonNULL if dnstap enabled.
* @param doq_table: the doq connection table, with shared information.
* @param rnd: random state.
* @param ssl_service_key: the SSL service key file.
* @param ssl_service_pem: the SSL service pem file.
* @param cfg: config file struct.
* @param cb: callback function when a request arrives. It is passed
* the packet and user argument. Return true to send a reply.
Expand All @@ -211,9 +210,9 @@ listen_create(struct comm_base* base, struct listen_port* ports,
size_t bufsize, int tcp_accept_count, int tcp_idle_timeout,
int harden_large_queries, uint32_t http_max_streams,
char* http_endpoint, int http_notls, struct tcl_list* tcp_conn_limit,
void* sslctx, struct dt_env* dtenv, struct doq_table* doq_table,
struct ub_randstate* rnd, const char* ssl_service_key,
const char* ssl_service_pem, struct config_file* cfg,
void* sslctx, void* quic_sslctx, struct dt_env* dtenv,
struct doq_table* doq_table,
struct ub_randstate* rnd,struct config_file* cfg,
comm_point_callback_type* cb, void *cb_arg);

/**
Expand Down Expand Up @@ -512,6 +511,15 @@ struct doq_table {
size_t current_size;
};

/**
* create SSL context for QUIC
* @param key: private key file.
* @param pem: public key cert.
* @param verifypem: if nonNULL, verifylocation file.
* return SSL_CTX* or NULL on failure (logged).
*/
void* quic_sslctx_create(char* key, char* pem, char* verifypem);

/** create doq table */
struct doq_table* doq_table_create(struct config_file* cfg,
struct ub_randstate* rnd);
Expand Down Expand Up @@ -712,9 +720,6 @@ int doq_timer_cmp(const void* key1, const void* key2);
/** compare function of doq_stream */
int doq_stream_cmp(const void* key1, const void* key2);

/** setup the doq_socket server tls context */
int doq_socket_setup_ctx(struct doq_server_socket* doq_socket);

/** setup the doq connection callbacks, and settings. */
int doq_conn_setup(struct doq_conn* conn, uint8_t* scid, size_t scidlen,
uint8_t* ocid, size_t ocidlen, const uint8_t* token, size_t tokenlen);
Expand Down
5 changes: 2 additions & 3 deletions testcode/fake_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -938,11 +938,10 @@ listen_create(struct comm_base* base, struct listen_port* ATTR_UNUSED(ports),
char* ATTR_UNUSED(http_endpoint),
int ATTR_UNUSED(http_notls),
struct tcl_list* ATTR_UNUSED(tcp_conn_limit),
void* ATTR_UNUSED(sslctx), struct dt_env* ATTR_UNUSED(dtenv),
void* ATTR_UNUSED(sslctx), void* ATTR_UNUSED(quic_ssl),
struct dt_env* ATTR_UNUSED(dtenv),
struct doq_table* ATTR_UNUSED(table),
struct ub_randstate* ATTR_UNUSED(rnd),
const char* ATTR_UNUSED(ssl_service_key),
const char* ATTR_UNUSED(ssl_service_pem),
struct config_file* ATTR_UNUSED(cfg),
comm_point_callback_type* cb, void *cb_arg)
{
Expand Down
6 changes: 6 additions & 0 deletions testcode/testbound.c
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,12 @@ void listen_desetup_locks(void)
}

#ifdef HAVE_NGTCP2
void* quic_sslctx_create(char* ATTR_UNUSED(key), char* ATTR_UNUSED(pem),
char* ATTR_UNUSED(verifypem))
{
return NULL;
}

void comm_point_doq_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(event),
void* ATTR_UNUSED(arg))
{
Expand Down
2 changes: 1 addition & 1 deletion util/net_help.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ int listen_sslctx_setup(void* ctxt);
*/
void listen_sslctx_setup_2(void* ctxt);

/**
/**
* create SSL listen context
* @param key: private key file.
* @param pem: public key cert.
Expand Down
Loading

0 comments on commit 61d7250

Please sign in to comment.