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