mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
vhost: check cert validity dates
After startup, and once per day, check the validity dates on our ssl certs, and broadcast callbacks with the information so interested plugins can know. If our clock is < May 2016, we don't try to judge the certs, because clearly we don't know what time it is.
This commit is contained in:
parent
fb4397f841
commit
a798db0e2b
7 changed files with 132 additions and 23 deletions
|
@ -196,7 +196,7 @@ lws_protocol_init(struct lws_context *context)
|
|||
struct lws_vhost *vh = context->vhost_list;
|
||||
const struct lws_protocol_vhost_options *pvo, *pvo1;
|
||||
struct lws wsi;
|
||||
int n;
|
||||
int n, any = 0;
|
||||
|
||||
if (context->doing_protocol_init)
|
||||
return 0;
|
||||
|
@ -212,7 +212,8 @@ lws_protocol_init(struct lws_context *context)
|
|||
wsi.vhost = vh;
|
||||
|
||||
/* only do the protocol init once for a given vhost */
|
||||
if (vh->created_vhost_protocols)
|
||||
if (vh->created_vhost_protocols ||
|
||||
(vh->options & LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT))
|
||||
goto next;
|
||||
|
||||
/* initialize supported protocols on this vhost */
|
||||
|
@ -260,6 +261,10 @@ lws_protocol_init(struct lws_context *context)
|
|||
pvo = pvo1->options;
|
||||
}
|
||||
|
||||
#if defined(LWS_OPENSSL_SUPPORT)
|
||||
any |= !!vh->ssl_ctx;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* inform all the protocols that they are doing their
|
||||
* one-time initialization if they want to.
|
||||
|
@ -289,6 +294,9 @@ next:
|
|||
|
||||
context->protocol_init_done = 1;
|
||||
|
||||
if (any)
|
||||
lws_tls_check_all_cert_lifetimes(context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1270,6 +1278,8 @@ lws_create_context(struct lws_context_creation_info *info)
|
|||
LWS_EXT_CB_CLIENT_CONTEXT_CONSTRUCT, NULL, 0) < 0)
|
||||
goto bail;
|
||||
|
||||
time(&context->last_cert_check_s);
|
||||
|
||||
#if defined(LWS_WITH_SELFTESTS)
|
||||
lws_jws_selftest();
|
||||
#endif
|
||||
|
|
|
@ -1432,12 +1432,45 @@ lws_rx_flow_allow_all_protocol(const struct lws_context *context,
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
lws_broadcast(struct lws_context *context, int reason, void *in, size_t len)
|
||||
{
|
||||
struct lws_vhost *v = context->vhost_list;
|
||||
struct lws wsi;
|
||||
int n, ret = 0;
|
||||
|
||||
memset(&wsi, 0, sizeof(wsi));
|
||||
wsi.context = context;
|
||||
|
||||
while (v) {
|
||||
const struct lws_protocols *p = v->protocols;
|
||||
wsi.vhost = v;
|
||||
|
||||
for (n = 0; n < v->count_protocols; n++) {
|
||||
wsi.protocol = p;
|
||||
if (p->callback &&
|
||||
p->callback(&wsi, reason, NULL, in, len))
|
||||
ret |= 1;
|
||||
p++;
|
||||
}
|
||||
v = v->vhost_next;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
LWS_VISIBLE extern const char *
|
||||
lws_canonical_hostname(struct lws_context *context)
|
||||
{
|
||||
return (const char *)context->canonical_hostname;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN const char *
|
||||
lws_get_vhost_name(struct lws_vhost *vhost)
|
||||
{
|
||||
return vhost->name;
|
||||
}
|
||||
|
||||
int user_callback_handle_rxflow(lws_callback_function callback_function,
|
||||
struct lws *wsi,
|
||||
enum lws_callback_reasons reason, void *user,
|
||||
|
|
|
@ -1422,6 +1422,12 @@ enum lws_callback_reasons {
|
|||
* callback is serialized in the lws event loop normally, even
|
||||
* if the lws_cancel_service[_pt]() call was from a different
|
||||
* thread. */
|
||||
LWS_CALLBACK_VHOST_CERT_AGING = 72,
|
||||
/**< When a vhost TLS cert has its expiry checked, this callback
|
||||
* is broadcast to every protocol of every vhost in case the
|
||||
* protocol wants to take some action with this information.
|
||||
* \p in is the lws_vhost and \p len is the number of days left
|
||||
* before it expires, as a (ssize_t) */
|
||||
|
||||
/****** add new things just above ---^ ******/
|
||||
|
||||
|
@ -2504,6 +2510,11 @@ enum lws_context_options {
|
|||
* LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS callback, which
|
||||
* provides the vhost SSL_CTX * in the user parameter.
|
||||
*/
|
||||
LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT = (1 << 25),
|
||||
/**< (VH) You probably don't want this. It forces this vhost to not
|
||||
* call LWS_CALLBACK_PROTOCOL_INIT on its protocols. It's used in the
|
||||
* special case of a temporary vhost bound to a single protocol.
|
||||
*/
|
||||
|
||||
/****** add new things just above ---^ ******/
|
||||
};
|
||||
|
@ -3013,6 +3024,14 @@ lws_vhost_get(struct lws *wsi) LWS_WARN_DEPRECATED;
|
|||
LWS_VISIBLE LWS_EXTERN struct lws_vhost *
|
||||
lws_get_vhost(struct lws *wsi);
|
||||
|
||||
/**
|
||||
* lws_get_vhost_name() - returns the name of a vhost
|
||||
*
|
||||
* \param vhost: which vhost
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN const char *
|
||||
lws_get_vhost_name(struct lws_vhost *vhost);
|
||||
|
||||
/**
|
||||
* lws_json_dump_vhost() - describe vhost state and stats in JSON
|
||||
*
|
||||
|
|
|
@ -1088,6 +1088,7 @@ struct lws_peer {
|
|||
struct lws_context {
|
||||
time_t last_timeout_check_s;
|
||||
time_t last_ws_ping_pong_check_s;
|
||||
time_t last_cert_check_s;
|
||||
time_t time_up;
|
||||
const struct lws_plat_file_ops *fops;
|
||||
struct lws_plat_file_ops fops_platform;
|
||||
|
@ -2368,6 +2369,7 @@ LWS_EXTERN void lwsl_emit_stderr(int level, const char *line);
|
|||
#define lws_ssl_remove_wsi_from_buffered_list(_a)
|
||||
#define lws_context_init_ssl_library(_a)
|
||||
#define lws_ssl_anybody_has_buffered_read_tsi(_a, _b) (0)
|
||||
#define lws_tls_check_all_cert_lifetimes(_a)
|
||||
#else
|
||||
#define LWS_SSL_ENABLED(context) (context->use_ssl)
|
||||
LWS_EXTERN int openssl_websocket_private_data_index;
|
||||
|
@ -2408,6 +2410,8 @@ lws_ssl_info_callback(const lws_tls_conn *ssl, int where, int ret);
|
|||
LWS_EXTERN int
|
||||
lws_tls_openssl_cert_info(X509 *x509, enum lws_tls_cert_info type,
|
||||
union lws_tls_cert_info_results *buf, size_t len);
|
||||
LWS_EXTERN int
|
||||
lws_tls_check_all_cert_lifetimes(struct lws_context *context);
|
||||
#ifndef LWS_NO_SERVER
|
||||
LWS_EXTERN int
|
||||
lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
||||
|
@ -2526,6 +2530,9 @@ lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len);
|
|||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_ssl_pending_no_ssl(struct lws *wsi);
|
||||
|
||||
int
|
||||
lws_tls_check_cert_lifetime(struct lws_vhost *vhost);
|
||||
|
||||
int lws_jws_selftest(void);
|
||||
|
||||
#ifdef LWS_WITH_HTTP_PROXY
|
||||
|
@ -2704,6 +2711,9 @@ lws_same_vh_protocol_remove(struct lws *wsi);
|
|||
LWS_EXTERN void
|
||||
lws_same_vh_protocol_insert(struct lws *wsi, int n);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_broadcast(struct lws_context *context, int reason, void *in, size_t len);
|
||||
|
||||
#if defined(LWS_WITH_STATS)
|
||||
void
|
||||
lws_stats_atomic_bump(struct lws_context * context,
|
||||
|
|
|
@ -1166,6 +1166,14 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* check the remaining cert lifetime daily
|
||||
*/
|
||||
if (context->last_cert_check_s < now - (24 * 60 * 60)) {
|
||||
context->last_cert_check_s = now;
|
||||
|
||||
lws_tls_check_all_cert_lifetimes(context);
|
||||
}
|
||||
|
||||
/* the socket we came to service timed out, nothing to do */
|
||||
if (timed_out)
|
||||
|
@ -1234,7 +1242,6 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
|
|||
switch (wsi->mode) {
|
||||
case LWSCM_EVENT_PIPE:
|
||||
{
|
||||
struct lws_vhost *v = context->vhost_list;
|
||||
#if !defined(WIN32) && !defined(_WIN32)
|
||||
char s[10];
|
||||
|
||||
|
@ -1248,31 +1255,18 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
|
|||
if (n < 0)
|
||||
goto close_and_handled;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* the poll() wait, or the event loop for libuv etc is a
|
||||
* process-wide resource that we interrupted. So let every
|
||||
* protocol that may be interested in the pipe event know that
|
||||
* it happened.
|
||||
*/
|
||||
while (v) {
|
||||
const struct lws_protocols *p = v->protocols;
|
||||
wsi->vhost = v;
|
||||
|
||||
for (n = 0; n < v->count_protocols; n++) {
|
||||
wsi->protocol = p;
|
||||
if (p->callback && p->callback(wsi,
|
||||
LWS_CALLBACK_EVENT_WAIT_CANCELLED,
|
||||
NULL, NULL, 0)) {
|
||||
lwsl_info("closed in event cancel\n");
|
||||
goto close_and_handled;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
v = v->vhost_next;
|
||||
if (lws_broadcast(context, LWS_CALLBACK_EVENT_WAIT_CANCELLED,
|
||||
NULL, 0)) {
|
||||
lwsl_info("closed in event cancel\n");
|
||||
goto close_and_handled;
|
||||
}
|
||||
wsi->vhost = NULL;
|
||||
wsi->protocol = NULL;
|
||||
|
||||
goto handled;
|
||||
}
|
||||
case LWSCM_HTTP_SERVING:
|
||||
|
|
|
@ -21,8 +21,9 @@
|
|||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
int lws_alloc_vfs_file(struct lws_context *context, const char *filename, uint8_t **buf,
|
||||
lws_filepos_t *amount)
|
||||
int
|
||||
lws_alloc_vfs_file(struct lws_context *context, const char *filename,
|
||||
uint8_t **buf, lws_filepos_t *amount)
|
||||
{
|
||||
lws_filepos_t len;
|
||||
lws_fop_flags_t flags = LWS_O_RDONLY;
|
||||
|
@ -97,6 +98,45 @@ lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
|
|||
wsi->pending_read_list_next = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
lws_tls_check_cert_lifetime(struct lws_vhost *v)
|
||||
{
|
||||
union lws_tls_cert_info_results ir;
|
||||
time_t now = (time_t)lws_now_secs(), life;
|
||||
int n;
|
||||
|
||||
if (!v->ssl_ctx)
|
||||
return -1;
|
||||
|
||||
if (now < 1464083026) /* May 2016 */
|
||||
/* our clock is wrong and we can't judge the certs */
|
||||
return -1;
|
||||
|
||||
n = lws_tls_vhost_cert_info(v, LWS_TLS_CERT_INFO_VALIDITY_TO, &ir, 0);
|
||||
if (n)
|
||||
return -1;
|
||||
|
||||
life = (ir.time - now) / (24 * 3600);
|
||||
lwsl_notice(" vhost %s: cert expiry: %dd\n", v->name, (int)life);
|
||||
|
||||
lws_broadcast(v->context, LWS_CALLBACK_VHOST_CERT_AGING, v,
|
||||
(size_t)(ssize_t)life);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_tls_check_all_cert_lifetimes(struct lws_context *context)
|
||||
{
|
||||
struct lws_vhost *v = context->vhost_list;
|
||||
|
||||
while (v) {
|
||||
lws_tls_check_cert_lifetime(v);
|
||||
v = v->vhost_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_gate_accepts(struct lws_context *context, int on)
|
||||
|
|
|
@ -411,6 +411,9 @@ callback_lws_sshd_demo(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
close(vhd->privileged_fd);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_VHOST_CERT_AGING:
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!vhd->ssh_base_protocol) {
|
||||
vhd->ssh_base_protocol = lws_vhost_name_to_protocol(
|
||||
|
|
Loading…
Add table
Reference in a new issue