/* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010 - 2019 Andy Green * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include "private-lib-core.h" /* * fakes POLLIN on all tls guys with buffered rx * * returns nonzero if any tls guys had POLLIN faked */ int lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt) { int ret = 0; lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1, lws_dll2_get_head(&pt->tls.dll_pending_tls_owner)) { struct lws *wsi = lws_container_of(p, struct lws, tls.dll_pending_tls); if (wsi->position_in_fds_table >= 0) { pt->fds[wsi->position_in_fds_table].revents |= pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN; ret |= pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN; } } lws_end_foreach_dll_safe(p, p1); return !!ret; } void __lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi) { lws_dll2_remove(&wsi->tls.dll_pending_tls); } void lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi) { struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; lws_pt_lock(pt, __func__); __lws_ssl_remove_wsi_from_buffered_list(wsi); lws_pt_unlock(pt); } #if defined(LWS_WITH_SERVER) int lws_tls_check_cert_lifetime(struct lws_vhost *v) { time_t now = (time_t)lws_now_secs(), life = 0; struct lws_acme_cert_aging_args caa; union lws_tls_cert_info_results ir; int n; if (v->tls.ssl_ctx && !v->tls.skipped_certs) { if (now < 1542933698) /* Nov 23 2018 00:42 UTC */ /* 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); } else lwsl_info(" vhost %s: no cert\n", v->name); memset(&caa, 0, sizeof(caa)); caa.vh = v; lws_broadcast(&v->context->pt[0], LWS_CALLBACK_VHOST_CERT_AGING, (void *)&caa, (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) { if (lws_tls_check_cert_lifetime(v) < 0) return -1; v = v->vhost_next; } return 0; } /* * LWS_TLS_EXTANT_NO : skip adding the cert * LWS_TLS_EXTANT_YES : use the cert and private key paths normally * LWS_TLS_EXTANT_ALTERNATIVE: normal paths not usable, try alternate if poss */ enum lws_tls_extant lws_tls_generic_cert_checks(struct lws_vhost *vhost, const char *cert, const char *private_key) { int n, m; /* * The user code can choose to either pass the cert and * key filepaths using the info members like this, or it can * leave them NULL; force the vhost SSL_CTX init using the info * options flag LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX; and * set up the cert himself using the user callback * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which * happened just above and has the vhost SSL_CTX * in the user * parameter. */ if (!cert || !private_key) return LWS_TLS_EXTANT_NO; n = lws_tls_use_any_upgrade_check_extant(cert); if (n == LWS_TLS_EXTANT_ALTERNATIVE) return LWS_TLS_EXTANT_ALTERNATIVE; m = lws_tls_use_any_upgrade_check_extant(private_key); if (m == LWS_TLS_EXTANT_ALTERNATIVE) return LWS_TLS_EXTANT_ALTERNATIVE; if ((n == LWS_TLS_EXTANT_NO || m == LWS_TLS_EXTANT_NO) && (vhost->options & LWS_SERVER_OPTION_IGNORE_MISSING_CERT)) { lwsl_notice("Ignoring missing %s or %s\n", cert, private_key); vhost->tls.skipped_certs = 1; return LWS_TLS_EXTANT_NO; } /* * the cert + key exist */ return LWS_TLS_EXTANT_YES; } /* * update the cert for every vhost using the given path */ int lws_tls_cert_updated(struct lws_context *context, const char *certpath, const char *keypath, const char *mem_cert, size_t len_mem_cert, const char *mem_privkey, size_t len_mem_privkey) { struct lws wsi; wsi.context = context; lws_start_foreach_ll(struct lws_vhost *, v, context->vhost_list) { wsi.vhost = v; /* not a real bound wsi */ if (v->tls.alloc_cert_path && v->tls.key_path && !strcmp(v->tls.alloc_cert_path, certpath) && !strcmp(v->tls.key_path, keypath)) { lws_tls_server_certs_load(v, &wsi, certpath, keypath, mem_cert, len_mem_cert, mem_privkey, len_mem_privkey); if (v->tls.skipped_certs) lwsl_notice("%s: vhost %s: cert unset\n", __func__, v->name); } } lws_end_foreach_ll(v, vhost_next); return 0; } #endif int lws_gate_accepts(struct lws_context *context, int on) { struct lws_vhost *v = context->vhost_list; lwsl_notice("%s: on = %d\n", __func__, on); #if defined(LWS_WITH_STATS) context->updated = 1; #endif while (v) { if (v->tls.use_ssl && v->lserv_wsi && lws_change_pollfd(v->lserv_wsi, (LWS_POLLIN) * !on, (LWS_POLLIN) * on)) lwsl_notice("Unable to set accept POLLIN %d\n", on); v = v->vhost_next; } return 0; } /* comma-separated alpn list, like "h2,http/1.1" to openssl alpn format */ int lws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len) { uint8_t *oos = os, *plen = NULL; if (!comma) return 0; while (*comma && len > 2) { if (!plen && *comma == ' ') { comma++; continue; } if (!plen) { plen = os++; len--; } if (*comma == ',') { *plen = lws_ptr_diff(os, plen + 1); plen = NULL; comma++; } else { *os++ = *comma++; len--; } } if (plen) *plen = lws_ptr_diff(os, plen + 1); *os = 0; return lws_ptr_diff(os, oos); }