• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2019 - 2021 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  * This file contains the stuff related to secure streams policy, it's always
25  * built if LWS_WITH_SECURE_STREAMS enabled.
26  */
27 
28 #include <private-lib-core.h>
29 
30 #if defined(LWS_WITH_SYS_SMD)
31 const lws_ss_policy_t pol_smd = {
32 	.flags			= 0, /* have to set something for windows */
33 };
34 #endif
35 
36 const lws_ss_policy_t *
lws_ss_policy_lookup(const struct lws_context * context,const char * streamtype)37 lws_ss_policy_lookup(const struct lws_context *context, const char *streamtype)
38 {
39 	const lws_ss_policy_t *p = context->pss_policies;
40 
41 	if (!streamtype)
42 		return NULL;
43 
44 #if defined(LWS_WITH_SYS_SMD)
45 	if (!strcmp(streamtype, LWS_SMD_STREAMTYPENAME))
46 		return &pol_smd;
47 #endif
48 
49 	while (p) {
50 		if (!strcmp(p->streamtype, streamtype))
51 			return p;
52 		p = p->next;
53 	}
54 
55 	return NULL;
56 }
57 
58 int
_lws_ss_set_metadata(lws_ss_metadata_t * omd,const char * name,const void * value,size_t len)59 _lws_ss_set_metadata(lws_ss_metadata_t *omd, const char *name,
60 		     const void *value, size_t len)
61 {
62 	/*
63 	 * If there was already a heap-based value, it's about to go out of
64 	 * scope due to us trashing the pointer.  So free it first and clear
65 	 * its flag indicating it's heap-based.
66 	 */
67 
68 	if (omd->value_on_lws_heap) {
69 		lws_free_set_NULL(omd->value__may_own_heap);
70 		omd->value_on_lws_heap = 0;
71 	}
72 
73 	// lwsl_notice("%s: %s %s\n", __func__, name, (const char *)value);
74 
75 	omd->name = name;
76 	omd->value__may_own_heap = (void *)value;
77 	omd->length = len;
78 
79 	return 0;
80 }
81 
82 int
lws_ss_set_metadata(struct lws_ss_handle * h,const char * name,const void * value,size_t len)83 lws_ss_set_metadata(struct lws_ss_handle *h, const char *name,
84 		    const void *value, size_t len)
85 {
86 	lws_ss_metadata_t *omd = lws_ss_get_handle_metadata(h, name);
87 
88 	lws_service_assert_loop_thread(h->context, h->tsi);
89 
90 	if (omd)
91 		return _lws_ss_set_metadata(omd, name, value, len);
92 
93 #if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
94 	if (h->policy->flags & LWSSSPOLF_DIRECT_PROTO_STR) {
95 		omd = lws_ss_get_handle_instant_metadata(h, name);
96 		if (!omd) {
97 			omd = lws_zalloc(sizeof(*omd), "imetadata");
98 			if (!omd) {
99 				lwsl_err("%s OOM\n", __func__);
100 				return 1;
101 			}
102 			omd->name = name;
103 			omd->next = h->instant_metadata;
104 			h->instant_metadata = omd;
105 		}
106 		omd->value__may_own_heap = (void *)value;
107 		omd->length = len;
108 
109 		return 0;
110 	}
111 #endif
112 
113 	lwsl_info("%s: unknown metadata %s\n", __func__, name);
114 	return 1;
115 }
116 
117 int
_lws_ss_alloc_set_metadata(lws_ss_metadata_t * omd,const char * name,const void * value,size_t len)118 _lws_ss_alloc_set_metadata(lws_ss_metadata_t *omd, const char *name,
119 			   const void *value, size_t len)
120 {
121 	uint8_t *p;
122 	int n;
123 
124 	if (omd->value_on_lws_heap) {
125 		lws_free_set_NULL(omd->value__may_own_heap);
126 		omd->value_on_lws_heap = 0;
127 	}
128 
129 	p = lws_malloc(len, __func__);
130 	if (!p)
131 		return 1;
132 
133 	n = _lws_ss_set_metadata(omd, name, p, len);
134 	if (n) {
135 		lws_free(p);
136 		return n;
137 	}
138 
139 	memcpy(p, value, len);
140 
141 	omd->value_on_lws_heap = 1;
142 
143 	return 0;
144 }
145 
146 int
lws_ss_alloc_set_metadata(struct lws_ss_handle * h,const char * name,const void * value,size_t len)147 lws_ss_alloc_set_metadata(struct lws_ss_handle *h, const char *name,
148 			  const void *value, size_t len)
149 {
150 	lws_ss_metadata_t *omd = lws_ss_get_handle_metadata(h, name);
151 
152 	lws_service_assert_loop_thread(h->context, h->tsi);
153 
154 	if (!omd) {
155 		lwsl_info("%s: unknown metadata %s\n", __func__, name);
156 		return 1;
157 	}
158 
159 	return _lws_ss_alloc_set_metadata(omd, name, value, len);
160 }
161 
162 int
lws_ss_get_metadata(struct lws_ss_handle * h,const char * name,const void ** value,size_t * len)163 lws_ss_get_metadata(struct lws_ss_handle *h, const char *name,
164 		    const void **value, size_t *len)
165 {
166 	lws_ss_metadata_t *omd = lws_ss_get_handle_metadata(h, name);
167 #if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
168 	int n;
169 #endif
170 
171 	lws_service_assert_loop_thread(h->context, h->tsi);
172 
173 	if (omd) {
174 		*value = omd->value__may_own_heap;
175 		*len = omd->length;
176 
177 		return 0;
178 	}
179 #if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
180 	if (!(h->policy->flags & LWSSSPOLF_DIRECT_PROTO_STR))
181 		goto bail;
182 
183 	n = lws_http_string_to_known_header(name, strlen(name));
184 	if (n != LWS_HTTP_NO_KNOWN_HEADER) {
185 		*len = (size_t)lws_hdr_total_length(h->wsi, n);
186 		if (!*len)
187 			goto bail;
188 		*value = lws_hdr_simple_ptr(h->wsi, n);
189 		if (!*value)
190 			goto bail;
191 
192 		return 0;
193 	}
194 #if defined(LWS_WITH_CUSTOM_HEADERS)
195 	n = lws_hdr_custom_length(h->wsi, (const char *)name,
196 				  (int)strlen(name));
197 	if (n <= 0)
198 		goto bail;
199 	*value = lwsac_use(&h->imd_ac, (size_t)(n+1), (size_t)(n+1));
200 	if (!*value) {
201 		lwsl_err("%s ac OOM\n", __func__);
202 		return 1;
203 	}
204 	if (lws_hdr_custom_copy(h->wsi, (char *)(*value), n+1, name,
205 				(int)strlen(name))) {
206 		/* waste n+1 bytes until ss is destryed */
207 		goto bail;
208 	}
209 	*len = (size_t)n;
210 
211 	return 0;
212 #endif
213 
214 bail:
215 #endif
216 	lwsl_info("%s: unknown metadata %s\n", __func__, name);
217 
218 	return 1;
219 }
220 
221 lws_ss_metadata_t *
lws_ss_get_handle_metadata(struct lws_ss_handle * h,const char * name)222 lws_ss_get_handle_metadata(struct lws_ss_handle *h, const char *name)
223 {
224 	int n;
225 
226 	lws_service_assert_loop_thread(h->context, h->tsi);
227 
228 	for (n = 0; n < h->policy->metadata_count; n++)
229 		if (!strcmp(name, h->metadata[n].name))
230 			return &h->metadata[n];
231 
232 	return NULL;
233 }
234 
235 #if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
236 lws_ss_metadata_t *
lws_ss_get_handle_instant_metadata(struct lws_ss_handle * h,const char * name)237 lws_ss_get_handle_instant_metadata(struct lws_ss_handle *h, const char *name)
238 {
239 	lws_ss_metadata_t *imd = h->instant_metadata;
240 
241 	while (imd) {
242 		if (!strcmp(name, imd->name))
243 			return imd;
244 		imd = imd->next;
245 	}
246 
247 	return NULL;
248 }
249 
250 #endif
251 
252 
253 lws_ss_metadata_t *
lws_ss_policy_metadata(const lws_ss_policy_t * p,const char * name)254 lws_ss_policy_metadata(const lws_ss_policy_t *p, const char *name)
255 {
256 	lws_ss_metadata_t *pmd = p->metadata;
257 
258 	while (pmd) {
259 		if (pmd->name && !strcmp(name, pmd->name))
260 			return pmd;
261 		pmd = pmd->next;
262 	}
263 
264 	return NULL;
265 }
266 
267 lws_ss_metadata_t *
lws_ss_policy_metadata_index(const lws_ss_policy_t * p,size_t index)268 lws_ss_policy_metadata_index(const lws_ss_policy_t *p, size_t index)
269 {
270 	lws_ss_metadata_t *pmd = p->metadata;
271 
272 	while (pmd) {
273 		if (pmd->length == index)
274 			return pmd;
275 		pmd = pmd->next;
276 	}
277 
278 	return NULL;
279 }
280 
281 #if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
282 static int
fe_lws_ss_destroy(struct lws_dll2 * d,void * user)283 fe_lws_ss_destroy(struct lws_dll2 *d, void *user)
284 {
285 	lws_ss_handle_t *h = lws_container_of(d, lws_ss_handle_t, list);
286 
287 	lws_ss_destroy(&h);
288 
289 	return 0;
290 }
291 #endif
292 
293 /*
294  * Dynamic policy: we want to one-time create the vhost for the policy and the
295  * trust store behind it.
296  *
297  * Static policy: We want to make use of a trust store / vhost from the policy and add to its
298  * ss-refcount.
299  */
300 
301 struct lws_vhost *
lws_ss_policy_ref_trust_store(struct lws_context * context,const lws_ss_policy_t * pol,char doref)302 lws_ss_policy_ref_trust_store(struct lws_context *context,
303 			      const lws_ss_policy_t *pol, char doref)
304 {
305 	struct lws_context_creation_info i;
306 	struct lws_vhost *v;
307 	int n;
308 
309 	memset(&i, 0, sizeof(i));
310 
311 	if (!pol->trust.store) {
312 		v = lws_get_vhost_by_name(context, "_ss_default");
313 		if (!v) {
314 			/* corner case... there's no trust store used */
315 			i.options = context->options;
316 			i.vhost_name = "_ss_default";
317 			i.port = CONTEXT_PORT_NO_LISTEN;
318 			v = lws_create_vhost(context, &i);
319 			if (!v) {
320 				lwsl_err("%s: failed to create vhost %s\n",
321 					 __func__, i.vhost_name);
322 
323 				return NULL;
324 			}
325 		}
326 
327 		goto accepted;
328 	}
329 	v = lws_get_vhost_by_name(context, pol->trust.store->name);
330 	if (v) {
331 		lwsl_debug("%s: vh already exists\n", __func__);
332 		goto accepted;
333 	}
334 
335 	i.options = context->options;
336 	i.vhost_name = pol->trust.store->name;
337 	lwsl_debug("%s: %s\n", __func__, i.vhost_name);
338 #if defined(LWS_WITH_TLS) && defined(LWS_WITH_CLIENT)
339 	i.client_ssl_ca_mem = pol->trust.store->ssx509[0]->ca_der;
340 	i.client_ssl_ca_mem_len = (unsigned int)
341 			pol->trust.store->ssx509[0]->ca_der_len;
342 #endif
343 	i.port = CONTEXT_PORT_NO_LISTEN;
344 	lwsl_info("%s: %s trust store initial '%s'\n", __func__,
345 		  i.vhost_name, pol->trust.store->ssx509[0]->vhost_name);
346 
347 	v = lws_create_vhost(context, &i);
348 	if (!v) {
349 		lwsl_err("%s: failed to create vhost %s\n",
350 			 __func__, i.vhost_name);
351 		return NULL;
352 	} else
353 		v->from_ss_policy = 1;
354 
355 	for (n = 1; v && n < pol->trust.store->count; n++) {
356 		lwsl_info("%s: add '%s' to trust store\n", __func__,
357 			  pol->trust.store->ssx509[n]->vhost_name);
358 #if defined(LWS_WITH_TLS)
359 		if (lws_tls_client_vhost_extra_cert_mem(v,
360 				pol->trust.store->ssx509[n]->ca_der,
361 				pol->trust.store->ssx509[n]->ca_der_len)) {
362 			lwsl_err("%s: add extra cert failed\n",
363 					__func__);
364 			return NULL;
365 		}
366 #endif
367 	}
368 
369 accepted:
370 #if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) || defined(LWS_WITH_SECURE_STREAMS_CPP)
371 	if (doref)
372 		v->ss_refcount++;
373 #endif
374 
375 	return v;
376 }
377 
378 #if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) || defined(LWS_WITH_SECURE_STREAMS_CPP)
379 int
lws_ss_policy_unref_trust_store(struct lws_context * context,const lws_ss_policy_t * pol)380 lws_ss_policy_unref_trust_store(struct lws_context *context,
381 				const lws_ss_policy_t *pol)
382 {
383 	struct lws_vhost *v;
384 	const char *name = "_ss_default";
385 
386 	if (pol->trust.store)
387 		name = pol->trust.store->name;
388 
389 	v = lws_get_vhost_by_name(context, name);
390 	if (!v || !v->from_ss_policy)
391 		return 0;
392 
393 	assert(v->ss_refcount);
394 
395 	v->ss_refcount--;
396 	if (!v->ss_refcount) {
397 		lwsl_notice("%s: destroying vh %s\n", __func__, name);
398 		lws_vhost_destroy(v);
399 	}
400 
401 	return 1;
402 }
403 #endif
404 
405 int
lws_ss_policy_set(struct lws_context * context,const char * name)406 lws_ss_policy_set(struct lws_context *context, const char *name)
407 {
408 	int ret = 0;
409 
410 #if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
411 	struct policy_cb_args *args = (struct policy_cb_args *)context->pol_args;
412 	const lws_ss_policy_t *pol;
413 	struct lws_vhost *v;
414 	lws_ss_x509_t *x;
415 	char buf[16];
416 	int m;
417 
418 	/*
419 	 * Parsing seems to have succeeded, and we're going to use the new
420 	 * policy that's laid out in args->ac
421 	 */
422 
423 	if (!args)
424 		return 1;
425 
426 	lejp_destruct(&args->jctx);
427 
428 	if (context->ac_policy) {
429 		int n;
430 
431 #if defined(LWS_WITH_SYS_METRICS)
432 		lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
433 					   context->owner_mtr_dynpol.head) {
434 			lws_metric_policy_dyn_t *dm =
435 				lws_container_of(d, lws_metric_policy_dyn_t, list);
436 
437 			lws_metric_policy_dyn_destroy(dm, 1); /* keep */
438 
439 		} lws_end_foreach_dll_safe(d, d1);
440 #endif
441 
442 		/*
443 		 * any existing ss created with the old policy have to go away
444 		 * now, since they point to the shortly-to-be-destroyed old
445 		 * policy
446 		 */
447 
448 		for (n = 0; n < context->count_threads; n++) {
449 			struct lws_context_per_thread *pt = &context->pt[n];
450 
451 			lws_dll2_foreach_safe(&pt->ss_owner, NULL, fe_lws_ss_destroy);
452 		}
453 
454 		/*
455 		 * So this is a bit fun-filled, we already had a policy in
456 		 * force, perhaps it was the default policy that's just good for
457 		 * fetching the real policy, and we're doing that now.
458 		 *
459 		 * We can destroy all the policy-related direct allocations
460 		 * easily because they're cleanly in a single lwsac...
461 		 */
462 		lwsac_free(&context->ac_policy);
463 
464 		/*
465 		 * ...but when we did the trust stores, we created vhosts for
466 		 * each.  We need to destroy those now too, and recreate new
467 		 * ones from the new policy, perhaps with different X.509s.
468 		 *
469 		 * Vhost destruction is inherently async, it can't be destroyed
470 		 * until all of the wsi bound to it have closed, and, eg, libuv
471 		 * means their closure is deferred until a later go around the
472 		 * event loop.  SMP means we also have to wait for all the pts
473 		 * to close their wsis that are bound on the vhost too.
474 		 *
475 		 * This marks the vhost as being destroyed so new things won't
476 		 * use it, and starts the close of all wsi on this pt that are
477 		 * bound to the wsi, and deals with the listen socket if any.
478 		 * "being-destroyed" vhosts can't be found using get_vhost_by_
479 		 * name(), so if a new vhost of the same name exists that isn't
480 		 * being destroyed that will be the one found.
481 		 *
482 		 * When the number of wsi bound to the vhost gets to zero a
483 		 * short time later, the vhost is actually destroyed.
484 		 */
485 
486 		v = context->vhost_list;
487 		while (v) {
488 			if (v->from_ss_policy) {
489 				struct lws_vhost *vh = v->vhost_next;
490 				lwsl_debug("%s: destroying %s\n", __func__, lws_vh_tag(v));
491 				lws_vhost_destroy(v);
492 				v = vh;
493 				continue;
494 			}
495 			v = v->vhost_next;
496 		}
497 	}
498 
499 	context->pss_policies = args->heads[LTY_POLICY].p;
500 	context->ac_policy = args->ac;
501 
502 	lws_humanize(buf, sizeof(buf), lwsac_total_alloc(args->ac),
503 			humanize_schema_si_bytes);
504 	if (lwsac_total_alloc(args->ac))
505 		m = (int)((lwsac_total_overhead(args->ac) * 100) /
506 				lwsac_total_alloc(args->ac));
507 	else
508 		m = 0;
509 
510 	(void)m;
511 	lwsl_info("%s: %s, pad %d%c: %s\n", __func__, buf, m, '%', name);
512 
513 	/* Create vhosts for each type of trust store */
514 
515 	/*
516 	 * We get called from context creation... instantiates
517 	 * vhosts with client tls contexts set up for each unique CA.
518 	 *
519 	 * We create the vhosts by walking streamtype list and create vhosts
520 	 * using trust store name if it's a client connection that doesn't
521 	 * already exist.
522 	 */
523 
524 	pol = context->pss_policies;
525 	while (pol) {
526 		if (!(pol->flags & LWSSSPOLF_SERVER)) {
527 			v = lws_ss_policy_ref_trust_store(context, pol,
528 						  0 /* no refcount inc */);
529 			if (!v)
530 				ret = 1;
531 		}
532 
533 		pol = pol->next;
534 	}
535 
536 #if defined(LWS_WITH_SOCKS5)
537 
538 	/*
539 	 * ... we need to go through every vhost updating its understanding of
540 	 * which socks5 proxy to use...
541 	 */
542 
543 	v = context->vhost_list;
544 	while (v) {
545 		lws_set_socks(v, args->socks5_proxy);
546 		v = v->vhost_next;
547 	}
548 	if (context->vhost_system)
549 		lws_set_socks(context->vhost_system, args->socks5_proxy);
550 
551 	if (args->socks5_proxy)
552 		lwsl_notice("%s: global socks5 proxy: %s\n", __func__,
553 			    args->socks5_proxy);
554 #endif
555 
556 	/*
557 	 * For dynamic policy case, now we processed the x.509 CAs, we can free
558 	 * all of our originals.  For static policy, they're in .rodata, nothing
559 	 * to free.
560 	 */
561 
562 	x = args->heads[LTY_X509].x;
563 	while (x) {
564 		/*
565 		 * Free all the client DER buffers now they have been parsed
566 		 * into tls library X.509 objects
567 		 */
568 		if (!x->keep) { /* used for server */
569 			lws_free((void *)x->ca_der);
570 			x->ca_der = NULL;
571 		}
572 
573 		x = x->next;
574 	}
575 
576 	context->last_policy = time(NULL);
577 #if defined(LWS_WITH_SYS_METRICS)
578 	if (context->pss_policies)
579 		((lws_ss_policy_t *)context->pss_policies)->metrics =
580 						args->heads[LTY_METRICS].m;
581 #endif
582 
583 	/* and we can discard the parsing args object now, invalidating args */
584 
585 	lws_free_set_NULL(context->pol_args);
586 #endif
587 
588 #if defined(LWS_WITH_SYS_METRICS)
589 	lws_metric_rebind_policies(context);
590 #endif
591 
592 #if defined(LWS_WITH_SYS_SMD)
593 	(void)lws_smd_msg_printf(context, LWSSMDCL_SYSTEM_STATE,
594 				 "{\"policy\":\"updated\",\"ts\":%lu}",
595 				   (long)context->last_policy);
596 #endif
597 
598 	return ret;
599 }
600