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 = (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 
56 void
__lws_ssl_remove_wsi_from_buffered_list(struct lws * wsi)57 __lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
58 {
59 	lws_dll2_remove(&wsi->tls.dll_pending_tls);
60 }
61 
62 void
lws_ssl_remove_wsi_from_buffered_list(struct lws * wsi)63 lws_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)
73 int
lws_tls_check_cert_lifetime(struct lws_vhost * v)74 lws_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_notice("   vhost %s: cert expiry: %dd\n", v->name,
94 			    (int)life);
95 	} else
96 		lwsl_info("   vhost %s: no cert\n", 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 
106 int
lws_tls_check_all_cert_lifetimes(struct lws_context * context)107 lws_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  */
125 enum lws_tls_extant
lws_tls_generic_cert_checks(struct lws_vhost * vhost,const char * cert,const char * private_key)126 lws_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_notice("Ignoring missing %s or %s\n", 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 
171 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)172 lws_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_notice("%s: vhost %s: cert unset\n",
192 					    __func__, v->name);
193 		}
194 	} lws_end_foreach_ll(v, vhost_next);
195 
196 	return 0;
197 }
198 #endif
199 
200 int
lws_gate_accepts(struct lws_context * context,int on)201 lws_gate_accepts(struct lws_context *context, int on)
202 {
203 	struct lws_vhost *v = context->vhost_list;
204 
205 	lwsl_notice("%s: on = %d\n", __func__, on);
206 
207 	while (v) {
208 		if (v->tls.use_ssl && v->lserv_wsi &&
209 		    lws_change_pollfd(v->lserv_wsi, (LWS_POLLIN) * !on,
210 				      (LWS_POLLIN) * on))
211 			lwsl_notice("Unable to set accept POLLIN %d\n", on);
212 
213 		v = v->vhost_next;
214 	}
215 
216 	return 0;
217 }
218 
219 /* comma-separated alpn list, like "h2,http/1.1" to openssl alpn format */
220 
221 int
lws_alpn_comma_to_openssl(const char * comma,uint8_t * os,int len)222 lws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len)
223 {
224 	uint8_t *oos = os, *plen = NULL;
225 
226 	if (!comma)
227 		return 0;
228 
229 	while (*comma && len > 2) {
230 		if (!plen && *comma == ' ') {
231 			comma++;
232 			continue;
233 		}
234 		if (!plen) {
235 			plen = os++;
236 			len--;
237 		}
238 
239 		if (*comma == ',') {
240 			*plen = (uint8_t)lws_ptr_diff(os, plen + 1);
241 			plen = NULL;
242 			comma++;
243 		} else {
244 			*os++ = (uint8_t)*comma++;
245 			len--;
246 		}
247 	}
248 
249 	if (plen)
250 		*plen = (uint8_t)lws_ptr_diff(os, plen + 1);
251 
252 	*os = 0;
253 
254 	return lws_ptr_diff(os, oos);
255 }
256 
257 
258 
259