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
33 int
lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread * pt)34 lws_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 |=
46 pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN;
47 ret |= pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN;
48 }
49
50 } lws_end_foreach_dll_safe(p, p1);
51
52 return !!ret;
53 }
54
55 void
__lws_ssl_remove_wsi_from_buffered_list(struct lws * wsi)56 __lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
57 {
58 lws_dll2_remove(&wsi->tls.dll_pending_tls);
59 }
60
61 void
lws_ssl_remove_wsi_from_buffered_list(struct lws * wsi)62 lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
63 {
64 struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
65
66 lws_pt_lock(pt, __func__);
67 __lws_ssl_remove_wsi_from_buffered_list(wsi);
68 lws_pt_unlock(pt);
69 }
70
71 #if defined(LWS_WITH_SERVER)
72 int
lws_tls_check_cert_lifetime(struct lws_vhost * v)73 lws_tls_check_cert_lifetime(struct lws_vhost *v)
74 {
75 time_t now = (time_t)lws_now_secs(), life = 0;
76 struct lws_acme_cert_aging_args caa;
77 union lws_tls_cert_info_results ir;
78 int n;
79
80 if (v->tls.ssl_ctx && !v->tls.skipped_certs) {
81
82 if (now < 1542933698) /* Nov 23 2018 00:42 UTC */
83 /* our clock is wrong and we can't judge the certs */
84 return -1;
85
86 n = lws_tls_vhost_cert_info(v, LWS_TLS_CERT_INFO_VALIDITY_TO,
87 &ir, 0);
88 if (n)
89 return 1;
90
91 life = (ir.time - now) / (24 * 3600);
92 lwsl_notice(" vhost %s: cert expiry: %dd\n", v->name,
93 (int)life);
94 } else
95 lwsl_info(" vhost %s: no cert\n", v->name);
96
97 memset(&caa, 0, sizeof(caa));
98 caa.vh = v;
99 lws_broadcast(&v->context->pt[0], LWS_CALLBACK_VHOST_CERT_AGING, (void *)&caa,
100 (size_t)(ssize_t)life);
101
102 return 0;
103 }
104
105 int
lws_tls_check_all_cert_lifetimes(struct lws_context * context)106 lws_tls_check_all_cert_lifetimes(struct lws_context *context)
107 {
108 struct lws_vhost *v = context->vhost_list;
109
110 while (v) {
111 if (lws_tls_check_cert_lifetime(v) < 0)
112 return -1;
113 v = v->vhost_next;
114 }
115
116 return 0;
117 }
118
119 /*
120 * LWS_TLS_EXTANT_NO : skip adding the cert
121 * LWS_TLS_EXTANT_YES : use the cert and private key paths normally
122 * LWS_TLS_EXTANT_ALTERNATIVE: normal paths not usable, try alternate if poss
123 */
124 enum lws_tls_extant
lws_tls_generic_cert_checks(struct lws_vhost * vhost,const char * cert,const char * private_key)125 lws_tls_generic_cert_checks(struct lws_vhost *vhost, const char *cert,
126 const char *private_key)
127 {
128 int n, m;
129
130 /*
131 * The user code can choose to either pass the cert and
132 * key filepaths using the info members like this, or it can
133 * leave them NULL; force the vhost SSL_CTX init using the info
134 * options flag LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX; and
135 * set up the cert himself using the user callback
136 * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which
137 * happened just above and has the vhost SSL_CTX * in the user
138 * parameter.
139 */
140
141 if (!cert || !private_key)
142 return LWS_TLS_EXTANT_NO;
143
144 n = lws_tls_use_any_upgrade_check_extant(cert);
145 if (n == LWS_TLS_EXTANT_ALTERNATIVE)
146 return LWS_TLS_EXTANT_ALTERNATIVE;
147 m = lws_tls_use_any_upgrade_check_extant(private_key);
148 if (m == LWS_TLS_EXTANT_ALTERNATIVE)
149 return LWS_TLS_EXTANT_ALTERNATIVE;
150
151 if ((n == LWS_TLS_EXTANT_NO || m == LWS_TLS_EXTANT_NO) &&
152 (vhost->options & LWS_SERVER_OPTION_IGNORE_MISSING_CERT)) {
153 lwsl_notice("Ignoring missing %s or %s\n", cert, private_key);
154 vhost->tls.skipped_certs = 1;
155
156 return LWS_TLS_EXTANT_NO;
157 }
158
159 /*
160 * the cert + key exist
161 */
162
163 return LWS_TLS_EXTANT_YES;
164 }
165
166 /*
167 * update the cert for every vhost using the given path
168 */
169
170 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)171 lws_tls_cert_updated(struct lws_context *context, const char *certpath,
172 const char *keypath,
173 const char *mem_cert, size_t len_mem_cert,
174 const char *mem_privkey, size_t len_mem_privkey)
175 {
176 struct lws wsi;
177
178 wsi.context = context;
179
180 lws_start_foreach_ll(struct lws_vhost *, v, context->vhost_list) {
181 wsi.vhost = v; /* not a real bound wsi */
182 if (v->tls.alloc_cert_path && v->tls.key_path &&
183 !strcmp(v->tls.alloc_cert_path, certpath) &&
184 !strcmp(v->tls.key_path, keypath)) {
185 lws_tls_server_certs_load(v, &wsi, certpath, keypath,
186 mem_cert, len_mem_cert,
187 mem_privkey, len_mem_privkey);
188
189 if (v->tls.skipped_certs)
190 lwsl_notice("%s: vhost %s: cert unset\n",
191 __func__, v->name);
192 }
193 } lws_end_foreach_ll(v, vhost_next);
194
195 return 0;
196 }
197 #endif
198
199 int
lws_gate_accepts(struct lws_context * context,int on)200 lws_gate_accepts(struct lws_context *context, int on)
201 {
202 struct lws_vhost *v = context->vhost_list;
203
204 lwsl_notice("%s: on = %d\n", __func__, on);
205
206 #if defined(LWS_WITH_STATS)
207 context->updated = 1;
208 #endif
209
210 while (v) {
211 if (v->tls.use_ssl && v->lserv_wsi &&
212 lws_change_pollfd(v->lserv_wsi, (LWS_POLLIN) * !on,
213 (LWS_POLLIN) * on))
214 lwsl_notice("Unable to set accept POLLIN %d\n", on);
215
216 v = v->vhost_next;
217 }
218
219 return 0;
220 }
221
222 /* comma-separated alpn list, like "h2,http/1.1" to openssl alpn format */
223
224 int
lws_alpn_comma_to_openssl(const char * comma,uint8_t * os,int len)225 lws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len)
226 {
227 uint8_t *oos = os, *plen = NULL;
228
229 if (!comma)
230 return 0;
231
232 while (*comma && len > 2) {
233 if (!plen && *comma == ' ') {
234 comma++;
235 continue;
236 }
237 if (!plen) {
238 plen = os++;
239 len--;
240 }
241
242 if (*comma == ',') {
243 *plen = lws_ptr_diff(os, plen + 1);
244 plen = NULL;
245 comma++;
246 } else {
247 *os++ = *comma++;
248 len--;
249 }
250 }
251
252 if (plen)
253 *plen = lws_ptr_diff(os, plen + 1);
254
255 *os = 0;
256
257 return lws_ptr_diff(os, oos);
258 }
259
260
261
262