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