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