1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 23d4afb5ceSopenharmony_ci */ 24d4afb5ceSopenharmony_ci 25d4afb5ceSopenharmony_ci#include "private-lib-core.h" 26d4afb5ceSopenharmony_ci 27d4afb5ceSopenharmony_ci/* 28d4afb5ceSopenharmony_ci * fakes POLLIN on all tls guys with buffered rx 29d4afb5ceSopenharmony_ci * 30d4afb5ceSopenharmony_ci * returns nonzero if any tls guys had POLLIN faked 31d4afb5ceSopenharmony_ci */ 32d4afb5ceSopenharmony_ci 33d4afb5ceSopenharmony_ciint 34d4afb5ceSopenharmony_cilws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt) 35d4afb5ceSopenharmony_ci{ 36d4afb5ceSopenharmony_ci int ret = 0; 37d4afb5ceSopenharmony_ci 38d4afb5ceSopenharmony_ci lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1, 39d4afb5ceSopenharmony_ci lws_dll2_get_head(&pt->tls.dll_pending_tls_owner)) { 40d4afb5ceSopenharmony_ci struct lws *wsi = lws_container_of(p, struct lws, 41d4afb5ceSopenharmony_ci tls.dll_pending_tls); 42d4afb5ceSopenharmony_ci 43d4afb5ceSopenharmony_ci if (wsi->position_in_fds_table >= 0) { 44d4afb5ceSopenharmony_ci 45d4afb5ceSopenharmony_ci pt->fds[wsi->position_in_fds_table].revents = (short) 46d4afb5ceSopenharmony_ci (pt->fds[wsi->position_in_fds_table].revents | 47d4afb5ceSopenharmony_ci (pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN)); 48d4afb5ceSopenharmony_ci ret |= pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN; 49d4afb5ceSopenharmony_ci } 50d4afb5ceSopenharmony_ci 51d4afb5ceSopenharmony_ci } lws_end_foreach_dll_safe(p, p1); 52d4afb5ceSopenharmony_ci 53d4afb5ceSopenharmony_ci return !!ret; 54d4afb5ceSopenharmony_ci} 55d4afb5ceSopenharmony_ci 56d4afb5ceSopenharmony_civoid 57d4afb5ceSopenharmony_ci__lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi) 58d4afb5ceSopenharmony_ci{ 59d4afb5ceSopenharmony_ci lws_dll2_remove(&wsi->tls.dll_pending_tls); 60d4afb5ceSopenharmony_ci} 61d4afb5ceSopenharmony_ci 62d4afb5ceSopenharmony_civoid 63d4afb5ceSopenharmony_cilws_ssl_remove_wsi_from_buffered_list(struct lws *wsi) 64d4afb5ceSopenharmony_ci{ 65d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 66d4afb5ceSopenharmony_ci 67d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 68d4afb5ceSopenharmony_ci __lws_ssl_remove_wsi_from_buffered_list(wsi); 69d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 70d4afb5ceSopenharmony_ci} 71d4afb5ceSopenharmony_ci 72d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 73d4afb5ceSopenharmony_ciint 74d4afb5ceSopenharmony_cilws_tls_check_cert_lifetime(struct lws_vhost *v) 75d4afb5ceSopenharmony_ci{ 76d4afb5ceSopenharmony_ci time_t now = (time_t)lws_now_secs(), life = 0; 77d4afb5ceSopenharmony_ci struct lws_acme_cert_aging_args caa; 78d4afb5ceSopenharmony_ci union lws_tls_cert_info_results ir; 79d4afb5ceSopenharmony_ci int n; 80d4afb5ceSopenharmony_ci 81d4afb5ceSopenharmony_ci if (v->tls.ssl_ctx && !v->tls.skipped_certs) { 82d4afb5ceSopenharmony_ci 83d4afb5ceSopenharmony_ci if (now < 1542933698) /* Nov 23 2018 00:42 UTC */ 84d4afb5ceSopenharmony_ci /* our clock is wrong and we can't judge the certs */ 85d4afb5ceSopenharmony_ci return -1; 86d4afb5ceSopenharmony_ci 87d4afb5ceSopenharmony_ci n = lws_tls_vhost_cert_info(v, LWS_TLS_CERT_INFO_VALIDITY_TO, 88d4afb5ceSopenharmony_ci &ir, 0); 89d4afb5ceSopenharmony_ci if (n) 90d4afb5ceSopenharmony_ci return 1; 91d4afb5ceSopenharmony_ci 92d4afb5ceSopenharmony_ci life = (ir.time - now) / (24 * 3600); 93d4afb5ceSopenharmony_ci lwsl_vhost_notice(v, " vhost %s: cert expiry: %dd", v->name, 94d4afb5ceSopenharmony_ci (int)life); 95d4afb5ceSopenharmony_ci } else 96d4afb5ceSopenharmony_ci lwsl_vhost_info(v, " vhost %s: no cert", v->name); 97d4afb5ceSopenharmony_ci 98d4afb5ceSopenharmony_ci memset(&caa, 0, sizeof(caa)); 99d4afb5ceSopenharmony_ci caa.vh = v; 100d4afb5ceSopenharmony_ci lws_broadcast(&v->context->pt[0], LWS_CALLBACK_VHOST_CERT_AGING, (void *)&caa, 101d4afb5ceSopenharmony_ci (size_t)(ssize_t)life); 102d4afb5ceSopenharmony_ci 103d4afb5ceSopenharmony_ci return 0; 104d4afb5ceSopenharmony_ci} 105d4afb5ceSopenharmony_ci 106d4afb5ceSopenharmony_ciint 107d4afb5ceSopenharmony_cilws_tls_check_all_cert_lifetimes(struct lws_context *context) 108d4afb5ceSopenharmony_ci{ 109d4afb5ceSopenharmony_ci struct lws_vhost *v = context->vhost_list; 110d4afb5ceSopenharmony_ci 111d4afb5ceSopenharmony_ci while (v) { 112d4afb5ceSopenharmony_ci if (lws_tls_check_cert_lifetime(v) < 0) 113d4afb5ceSopenharmony_ci return -1; 114d4afb5ceSopenharmony_ci v = v->vhost_next; 115d4afb5ceSopenharmony_ci } 116d4afb5ceSopenharmony_ci 117d4afb5ceSopenharmony_ci return 0; 118d4afb5ceSopenharmony_ci} 119d4afb5ceSopenharmony_ci 120d4afb5ceSopenharmony_ci/* 121d4afb5ceSopenharmony_ci * LWS_TLS_EXTANT_NO : skip adding the cert 122d4afb5ceSopenharmony_ci * LWS_TLS_EXTANT_YES : use the cert and private key paths normally 123d4afb5ceSopenharmony_ci * LWS_TLS_EXTANT_ALTERNATIVE: normal paths not usable, try alternate if poss 124d4afb5ceSopenharmony_ci */ 125d4afb5ceSopenharmony_cienum lws_tls_extant 126d4afb5ceSopenharmony_cilws_tls_generic_cert_checks(struct lws_vhost *vhost, const char *cert, 127d4afb5ceSopenharmony_ci const char *private_key) 128d4afb5ceSopenharmony_ci{ 129d4afb5ceSopenharmony_ci int n, m; 130d4afb5ceSopenharmony_ci 131d4afb5ceSopenharmony_ci /* 132d4afb5ceSopenharmony_ci * The user code can choose to either pass the cert and 133d4afb5ceSopenharmony_ci * key filepaths using the info members like this, or it can 134d4afb5ceSopenharmony_ci * leave them NULL; force the vhost SSL_CTX init using the info 135d4afb5ceSopenharmony_ci * options flag LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX; and 136d4afb5ceSopenharmony_ci * set up the cert himself using the user callback 137d4afb5ceSopenharmony_ci * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which 138d4afb5ceSopenharmony_ci * happened just above and has the vhost SSL_CTX * in the user 139d4afb5ceSopenharmony_ci * parameter. 140d4afb5ceSopenharmony_ci */ 141d4afb5ceSopenharmony_ci 142d4afb5ceSopenharmony_ci if (!cert || !private_key) 143d4afb5ceSopenharmony_ci return LWS_TLS_EXTANT_NO; 144d4afb5ceSopenharmony_ci 145d4afb5ceSopenharmony_ci n = (int)lws_tls_use_any_upgrade_check_extant(cert); 146d4afb5ceSopenharmony_ci if (n == LWS_TLS_EXTANT_ALTERNATIVE) 147d4afb5ceSopenharmony_ci return LWS_TLS_EXTANT_ALTERNATIVE; 148d4afb5ceSopenharmony_ci m = (int)lws_tls_use_any_upgrade_check_extant(private_key); 149d4afb5ceSopenharmony_ci if (m == LWS_TLS_EXTANT_ALTERNATIVE) 150d4afb5ceSopenharmony_ci return LWS_TLS_EXTANT_ALTERNATIVE; 151d4afb5ceSopenharmony_ci 152d4afb5ceSopenharmony_ci if ((n == LWS_TLS_EXTANT_NO || m == LWS_TLS_EXTANT_NO) && 153d4afb5ceSopenharmony_ci (vhost->options & LWS_SERVER_OPTION_IGNORE_MISSING_CERT)) { 154d4afb5ceSopenharmony_ci lwsl_vhost_notice(vhost, "Ignoring missing %s or %s", cert, private_key); 155d4afb5ceSopenharmony_ci vhost->tls.skipped_certs = 1; 156d4afb5ceSopenharmony_ci 157d4afb5ceSopenharmony_ci return LWS_TLS_EXTANT_NO; 158d4afb5ceSopenharmony_ci } 159d4afb5ceSopenharmony_ci 160d4afb5ceSopenharmony_ci /* 161d4afb5ceSopenharmony_ci * the cert + key exist 162d4afb5ceSopenharmony_ci */ 163d4afb5ceSopenharmony_ci 164d4afb5ceSopenharmony_ci return LWS_TLS_EXTANT_YES; 165d4afb5ceSopenharmony_ci} 166d4afb5ceSopenharmony_ci 167d4afb5ceSopenharmony_ci/* 168d4afb5ceSopenharmony_ci * update the cert for every vhost using the given path 169d4afb5ceSopenharmony_ci */ 170d4afb5ceSopenharmony_ci 171d4afb5ceSopenharmony_ciint 172d4afb5ceSopenharmony_cilws_tls_cert_updated(struct lws_context *context, const char *certpath, 173d4afb5ceSopenharmony_ci const char *keypath, 174d4afb5ceSopenharmony_ci const char *mem_cert, size_t len_mem_cert, 175d4afb5ceSopenharmony_ci const char *mem_privkey, size_t len_mem_privkey) 176d4afb5ceSopenharmony_ci{ 177d4afb5ceSopenharmony_ci struct lws wsi; 178d4afb5ceSopenharmony_ci 179d4afb5ceSopenharmony_ci wsi.a.context = context; 180d4afb5ceSopenharmony_ci 181d4afb5ceSopenharmony_ci lws_start_foreach_ll(struct lws_vhost *, v, context->vhost_list) { 182d4afb5ceSopenharmony_ci wsi.a.vhost = v; /* not a real bound wsi */ 183d4afb5ceSopenharmony_ci if (v->tls.alloc_cert_path && v->tls.key_path && 184d4afb5ceSopenharmony_ci !strcmp(v->tls.alloc_cert_path, certpath) && 185d4afb5ceSopenharmony_ci !strcmp(v->tls.key_path, keypath)) { 186d4afb5ceSopenharmony_ci lws_tls_server_certs_load(v, &wsi, certpath, keypath, 187d4afb5ceSopenharmony_ci mem_cert, len_mem_cert, 188d4afb5ceSopenharmony_ci mem_privkey, len_mem_privkey); 189d4afb5ceSopenharmony_ci 190d4afb5ceSopenharmony_ci if (v->tls.skipped_certs) 191d4afb5ceSopenharmony_ci lwsl_vhost_notice(v, "vhost %s: cert unset", v->name); 192d4afb5ceSopenharmony_ci } 193d4afb5ceSopenharmony_ci } lws_end_foreach_ll(v, vhost_next); 194d4afb5ceSopenharmony_ci 195d4afb5ceSopenharmony_ci return 0; 196d4afb5ceSopenharmony_ci} 197d4afb5ceSopenharmony_ci 198d4afb5ceSopenharmony_ciint 199d4afb5ceSopenharmony_cilws_gate_accepts(struct lws_context *context, int on) 200d4afb5ceSopenharmony_ci{ 201d4afb5ceSopenharmony_ci struct lws_vhost *v = context->vhost_list; 202d4afb5ceSopenharmony_ci 203d4afb5ceSopenharmony_ci lwsl_notice("%s: on = %d\n", __func__, on); 204d4afb5ceSopenharmony_ci 205d4afb5ceSopenharmony_ci if (context->tls_gate_accepts == (char)on) 206d4afb5ceSopenharmony_ci return 0; 207d4afb5ceSopenharmony_ci 208d4afb5ceSopenharmony_ci context->tls_gate_accepts = (char)on; 209d4afb5ceSopenharmony_ci 210d4afb5ceSopenharmony_ci while (v) { 211d4afb5ceSopenharmony_ci lws_start_foreach_dll(struct lws_dll2 *, d, 212d4afb5ceSopenharmony_ci lws_dll2_get_head(&v->listen_wsi)) { 213d4afb5ceSopenharmony_ci struct lws *wsi = lws_container_of(d, struct lws, 214d4afb5ceSopenharmony_ci listen_list); 215d4afb5ceSopenharmony_ci 216d4afb5ceSopenharmony_ci if (v->tls.use_ssl && 217d4afb5ceSopenharmony_ci lws_change_pollfd(wsi, on ? LWS_POLLIN : 0, 218d4afb5ceSopenharmony_ci on ? 0 : LWS_POLLIN)) 219d4afb5ceSopenharmony_ci lwsl_cx_notice(context, "Unable to set POLLIN %d", on); 220d4afb5ceSopenharmony_ci } lws_end_foreach_dll(d); 221d4afb5ceSopenharmony_ci 222d4afb5ceSopenharmony_ci v = v->vhost_next; 223d4afb5ceSopenharmony_ci } 224d4afb5ceSopenharmony_ci 225d4afb5ceSopenharmony_ci return 0; 226d4afb5ceSopenharmony_ci} 227d4afb5ceSopenharmony_ci#endif 228d4afb5ceSopenharmony_ci 229d4afb5ceSopenharmony_ci/* comma-separated alpn list, like "h2,http/1.1" to openssl alpn format */ 230d4afb5ceSopenharmony_ci 231d4afb5ceSopenharmony_ciint 232d4afb5ceSopenharmony_cilws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len) 233d4afb5ceSopenharmony_ci{ 234d4afb5ceSopenharmony_ci uint8_t *oos = os, *plen = NULL; 235d4afb5ceSopenharmony_ci 236d4afb5ceSopenharmony_ci if (!comma) 237d4afb5ceSopenharmony_ci return 0; 238d4afb5ceSopenharmony_ci 239d4afb5ceSopenharmony_ci while (*comma && len > 2) { 240d4afb5ceSopenharmony_ci if (!plen && *comma == ' ') { 241d4afb5ceSopenharmony_ci comma++; 242d4afb5ceSopenharmony_ci continue; 243d4afb5ceSopenharmony_ci } 244d4afb5ceSopenharmony_ci if (!plen) { 245d4afb5ceSopenharmony_ci plen = os++; 246d4afb5ceSopenharmony_ci len--; 247d4afb5ceSopenharmony_ci } 248d4afb5ceSopenharmony_ci 249d4afb5ceSopenharmony_ci if (*comma == ',') { 250d4afb5ceSopenharmony_ci *plen = (uint8_t)lws_ptr_diff(os, plen + 1); 251d4afb5ceSopenharmony_ci plen = NULL; 252d4afb5ceSopenharmony_ci comma++; 253d4afb5ceSopenharmony_ci } else { 254d4afb5ceSopenharmony_ci *os++ = (uint8_t)*comma++; 255d4afb5ceSopenharmony_ci len--; 256d4afb5ceSopenharmony_ci } 257d4afb5ceSopenharmony_ci } 258d4afb5ceSopenharmony_ci 259d4afb5ceSopenharmony_ci if (plen) 260d4afb5ceSopenharmony_ci *plen = (uint8_t)lws_ptr_diff(os, plen + 1); 261d4afb5ceSopenharmony_ci 262d4afb5ceSopenharmony_ci *os = 0; 263d4afb5ceSopenharmony_ci 264d4afb5ceSopenharmony_ci return lws_ptr_diff(os, oos); 265d4afb5ceSopenharmony_ci} 266d4afb5ceSopenharmony_ci 267d4afb5ceSopenharmony_ci 268d4afb5ceSopenharmony_ci 269