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